Project

General

Profile

Revision 1426

Added by Jing Tao over 18 years ago

Move the permission checking part.

View differences:

src/edu/ucsb/nceas/metacat/AccessControlList.java
646 646
    return txtPerm.append("\"").toString();
647 647
  }
648 648

  
649
  
650 649
  /**
651
    * Check if a document id is a access document. Access document need user
652
    * has "all" permission to access it.
653
    * @param docId, the document id need to be checked
654
    */
655
    private static boolean isAccessDocument(String docId) throws SQLException
656
    {
657
      //detele the rev number if docid contains it
658
      docId=MetaCatUtil.getDocIdFromString(docId);
659
      PreparedStatement pStmt=null;
660
      DBConnection conn = null;
661
      int serialNumber = -1;
662
      try
663
      {
664
        //check out DBConnection
665
        conn=DBConnectionPool.getDBConnection("AccessControlList.isAccessDoc");
666
        serialNumber=conn.getCheckOutSerialNumber();
667
        pStmt = conn.prepareStatement("select 'x' from xml_access where " +
668
                                      "accessfileid like '" + docId +  "'");
669
        pStmt.execute();
670
        ResultSet rs = pStmt.getResultSet();
671
        boolean hasRow = rs.next();
672
        pStmt.close();
673
        if(hasRow)
674
        {
675
          return true;
676
        }
677
      }
678
      catch(SQLException e)
679
      {
680
       
681
        throw new SQLException("AccessControlList.isAccessDocument " +
682
                     "Error checking" +
683
                     " on document " + docId + ". " + e.getMessage());
684
      }
685
      finally
686
      {
687
        try
688
        {
689
           pStmt.close();
690
        }
691
        finally
692
        {
693
          DBConnectionPool.returnDBConnection(conn, serialNumber);
694
        }
695
      }
696
      return false;
697
    }//isAccessDocument
698
     
699
  /**
700
    * To create a part of query: "docid like '" +str1+ "', " +"docid like '" 
701
    * +str2+"'" ... We need to check user, group and public together for the 
702
    * permission. So we need the principal in an array and according the array
703
    * to create a part of query which will be used in other methods
704
    * @param principals, a string array storing the username, groups name and
705
    * public.
706
    */
707
   private String partQueryAboutDocId( String [] principals)
708
   {
709
     String partQuery="";
710
     int lengthOfArray=principals.length;
711
     
712
     for (int i=0;i<(lengthOfArray-1);i++)
713
     {
714
        partQuery=partQuery+"docid like '"+principals[i]+"',";
715
     }
716
     
717
     //the last one dosen't has "'"
718
     partQuery=partQuery+"docid like '"+principals[(lengthOfArray-1)]+"'";
719
     return partQuery;
720
     
721
   }
722
  
723
  /**
724
    * Check if a stirng array contains a given documents' owner
725
    * @param principals, a string array storing the username, groups name and
726
    * public.
727
    * @param docid, the id of given documents 
728
    */ 
729
  private static boolean containDocumentOwner( String [] principals, 
730
                                                              String docId)
731
                    throws SQLException
732
  {
733
    int lengthOfArray=principals.length;
734
    boolean hasRow; 
735
    PreparedStatement pStmt=null;
736
    DBConnection conn = null;
737
    int serialNumber = -1;
738
    
739
    try
740
    {
741
      //check out DBConnection
742
     conn=DBConnectionPool.getDBConnection("AccessControlList.containDocOnwer");
743
      serialNumber=conn.getCheckOutSerialNumber();
744
      pStmt = conn.prepareStatement(
745
                "SELECT 'x' FROM xml_documents " +
746
                "WHERE docid = ? AND user_owner = ?"); 
747
      //check every element in the string array too see if it conatains
748
      //the owner of document
749
      for (int i=0; i<lengthOfArray; i++)
750
      {
751
             
752
        // Bind the values to the query
753
        pStmt.setString(1, docId);
754
        pStmt.setString(2, principals[i]);
755

  
756
        pStmt.execute();
757
        ResultSet rs = pStmt.getResultSet();
758
        hasRow = rs.next();
759
        if (hasRow) 
760
        {
761
          pStmt.close();
762
          return true;
763
        }//if    
764
     
765
      }//for
766
    }//try
767
    catch (SQLException e) 
768
    {
769
        pStmt.close();
770
       
771
        throw new 
772
        SQLException("AccessControlList.hasPermission(). " +
773
                     "Error checking ownership for " + principals[0] +
774
                     " on document #" + docId + ". " + e.getMessage());
775
    }//catch
776
    finally
777
    {
778
      try
779
      {
780
        pStmt.close();
781
      }
782
      finally
783
      {
784
        DBConnectionPool.returnDBConnection(conn, serialNumber);
785
      }
786
    }
787
    return false; 
788
  }//containDocumentOwner
789
  
790
  /**
791
    * Check if the permission order for user at that documents is allowFirst
792
    * @param principals, list of names of principals to check for 
793
    * @param docid, document identifier to check for
794
    */
795
  private static boolean isAllowFirst(String [] principals, String docId)
796
                  throws SQLException, Exception
797
  {
798
    int lengthOfArray=principals.length;
799
    boolean hasRow;
800
    PreparedStatement pStmt = null;
801
    DBConnection conn = null;
802
    int serialNumber = -1;
803
    try
804
    {
805
      //check out DBConnection
806
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
807
      serialNumber=conn.getCheckOutSerialNumber();
808
    
809
      //select permission order from database
810
      pStmt = conn.prepareStatement(
811
                "SELECT perm_order FROM xml_access " +
812
                "WHERE principal_name= ? AND docid = ?");
813
   
814
      //check every name in the array
815
      for (int i=0; i<lengthOfArray;i++)
816
      {
817
        //bind value
818
        pStmt.setString(1, principals[i]);//user name
819
        pStmt.setString(2, docId);//docid
820
    
821
        pStmt.execute();
822
        ResultSet rs = pStmt.getResultSet();
823
        hasRow=rs.next();
824
        if (hasRow)
825
        {
826
          //get the permission order from data base
827
          String permissionOrder=rs.getString(1);
828
          //if the permission order is "allowFirst
829
          if (permissionOrder.equalsIgnoreCase(ALLOWFIRST))
830
          {
831
            pStmt.close();
832
            return true;
833
          }
834
          else
835
          {
836
            pStmt.close();
837
            return false;
838
          }
839
        }//if
840
      }//for
841
    }//try
842
    catch (SQLException e)
843
    {
844
      throw e;
845
    }
846
    finally
847
    {
848
      try
849
      {
850
        pStmt.close();
851
      }
852
      finally
853
      {
854
        DBConnectionPool.returnDBConnection(conn, serialNumber);
855
      }
856
    }
857
    
858
    //if reach here, means there is no permssion record for given names and 
859
    //docid. So throw a exception.
860
    
861
    throw new Exception("There is no permission record for user"+principals[0]+
862
                        "at document "+docId);
863
        
864
  }//isAllowFirst
865
  
866
  /**
867
    * Check if the users array has allow rules for given users, docid and 
868
    * permission.
869
    * If it has permission rule and ticket count is greater than 0, the ticket
870
    * number will decrease one for every allow rule
871
    * @param principals, list of names of principals to check for 
872
    * @param docid, document identifier to check for
873
    * @param permission, the permssion need to check
874
    */
875
  private static boolean hasAllowRule(String [] principals, String docId, 
876
                                  String permission)
877
                  throws SQLException, Exception
878
 {
879
   int lengthOfArray=principals.length;
880
   boolean allow=false;//initial value is no allow rule
881
   ResultSet rs;
882
   PreparedStatement pStmt = null;
883
   int permissionValue=intValue(permission);
884
   int permissionValueInTable;
885
   int ticketCount;
886
   DBConnection conn = null;
887
   int serialNumber = -1;
888
   try
889
   {
890
     //check out DBConnection
891
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
892
     serialNumber=conn.getCheckOutSerialNumber();
893
    //This sql statement will select entry with 
894
    //begin_time<=currentTime<=end_time in xml_access table
895
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
896
    //function will assign begin_time=sysdate
897
    pStmt = conn.prepareStatement(
898
                "SELECT permission " +
899
                "FROM xml_access " +
900
                "WHERE docid = ? " + 
901
                "AND principal_name = ? " +
902
                "AND perm_type = ? ");
903
    //bind docid, perm_type
904
    pStmt.setString(1, docId);
905
    pStmt.setString(3, ALLOW);
906
   
907
    //bind every elenment in user name array
908
    for (int i=0;i<lengthOfArray; i++)
909
    {
910
      pStmt.setString(2, principals[i]);
911
      pStmt.execute();
912
      rs=pStmt.getResultSet();
913
      while (rs.next())//check every entry for one user
914
      {
915
        permissionValueInTable=rs.getInt(1);
916
            
917
        //permission is ok  
918
        //the user have a permission to access the file
919
        if (( permissionValueInTable & permissionValue )== permissionValue )
920
        {
921
           allow=true;//has allow rule entry
922
        }//if
923
      }//while
924
    }//for
925
   }//try
926
   catch (SQLException sqlE)
927
   {
928
     throw sqlE;
929
   }
930
   catch (Exception e)
931
   {
932
     throw e;
933
   }
934
   finally
935
   {
936
     try
937
     {
938
       pStmt.close();
939
     }
940
     finally
941
     {
942
       DBConnectionPool.returnDBConnection(conn, serialNumber);
943
     }
944
   }
945
    return allow;
946
 }//hasAllowRule
947
 
948
 
949
   
950
   /**
951
    * Check if the users array has explicit deny rules for given users, docid 
952
    * and permission. That means the perm_type is deny and current time is
953
    * less than end_time and greater than begin time, or no time limit.
954
    * @param principals, list of names of principals to check for 
955
    * @param docid, document identifier to check for
956
    * @param permission, the permssion need to check
957
    */
958
  private static boolean hasExplicitDenyRule(String [] principals, String docId, 
959
                                  String permission)
960
                  throws SQLException
961
 {
962
   int lengthOfArray=principals.length;
963
   ResultSet rs;
964
   PreparedStatement pStmt = null;
965
   int permissionValue=intValue(permission);
966
   int permissionValueInTable;
967
   DBConnection conn = null;
968
   int serialNumber = -1;
969
   
970
   try
971
   {
972
     //check out DBConnection
973
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasExplicitDeny");
974
     serialNumber=conn.getCheckOutSerialNumber();
975
   
976
     pStmt = conn.prepareStatement(
977
                "SELECT permission " +
978
                "FROM xml_access " +
979
                "WHERE docid = ? " + 
980
                "AND principal_name = ? " +
981
                "AND perm_type = ? ");
982
    //bind docid, perm_type
983
    pStmt.setString(1, docId);
984
    pStmt.setString(3, DENY);
985
   
986
    //bind every elenment in user name array
987
    for (int i=0;i<lengthOfArray; i++)
988
    {
989
      pStmt.setString(2, principals[i]);
990
      pStmt.execute();
991
      rs=pStmt.getResultSet();
992
      while (rs.next())//check every entry for one user
993
      {
994
        permissionValueInTable=rs.getInt(1);
995
        
996
        //permission is ok the user doesn't have permission to access the file
997
        if (( permissionValueInTable & permissionValue )== permissionValue )
998
             
999
        {
1000
           pStmt.close();
1001
           return true;
1002
         }//if
1003
      }//while
1004
    }//for
1005
   }//try
1006
   catch (SQLException e)
1007
   {
1008
     throw e;
1009
   }//catch
1010
   finally
1011
   {
1012
     try
1013
     {
1014
       pStmt.close();
1015
     }
1016
     finally
1017
     {
1018
       DBConnectionPool.returnDBConnection(conn, serialNumber);
1019
     }
1020
   }//finally
1021
   return false;//no deny rule
1022
  }//hasExplicitDenyRule 
1023
   
1024

  
1025
  /**
1026
    * Creat a users pakages to check permssion rule, user itself, public and
1027
    * the gourps the user belong will be include in this package
1028
    * @param user, the name of user
1029
    * @param groups, the string array of the groups that user belong to
1030
    */
1031
  private static String [] createUsersPackage(String user, String [] groups)
1032
  {
1033
    String [] usersPackage=null;
1034
    int lengthOfPackage;
1035
    
1036
    if (groups!=null)
1037
    {
1038
      //if gouprs is not null and user is not public, we should create a array 
1039
      //to store the groups and user and public. 
1040
      //So the length of userPackage is the length of group plus two
1041
      if (!user.equalsIgnoreCase(PUBLIC))
1042
      {
1043
        lengthOfPackage=(groups.length)+2;
1044
        usersPackage=new String [lengthOfPackage];
1045
        //the first two elements is user self and public
1046
        usersPackage[0]=user;
1047
        usersPackage[1]=PUBLIC;
1048
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
1049
        //from index 2 to lengthOfPackage-1
1050
        for (int i=2; i<lengthOfPackage; i++)
1051
        {
1052
          usersPackage[i]=groups[i-2];
1053
        } //for
1054
      }//if user!=public
1055
      else//use=public
1056
      {
1057
        lengthOfPackage=(groups.length)+1;
1058
        usersPackage=new String [lengthOfPackage];
1059
        //the first lements is public
1060
        usersPackage[0]=PUBLIC;
1061
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
1062
        //from index 1 to lengthOfPackage-1
1063
        for (int i=1; i<lengthOfPackage; i++)
1064
        {
1065
          usersPackage[i]=groups[i-1];
1066
        } //for
1067
      }//else user=public
1068
       
1069
    }//if groups!=null
1070
    else
1071
    {
1072
      //because no groups, the userPackage only need two elements
1073
      //one is for user, the other is for public
1074
      if (!user.equalsIgnoreCase(PUBLIC))
1075
      {
1076
        lengthOfPackage=2;
1077
        usersPackage=new String [lengthOfPackage];
1078
        usersPackage[0]=user;
1079
        usersPackage[1]=PUBLIC;
1080
      }//if user!=public
1081
      else //user==public
1082
      {
1083
        //only put public into array
1084
        lengthOfPackage=1;
1085
        usersPackage=new String [lengthOfPackage];
1086
        usersPackage[0]=PUBLIC;
1087
      }
1088
    }//else groups==null
1089
    return usersPackage;
1090
  }//createUsersPackage
1091
 
1092
  /**
1093
    * This method will return a data set id for given access id.
1094
    * @param accessDocId, the accessDocId which need to be found data set id
1095
   */
1096
  private static String getDataSetId(String accessDocId) 
1097
                              throws SQLException
1098
  {
1099
    String dataSetId=null;
1100
    PreparedStatement pStmt=null;
1101
    ResultSet rs=null;
1102
    DBConnection conn=null;
1103
    int serialNumber=-1;
1104
    String query="SELECT docId from xml_relation where subject = ? or "
1105
                                                +"object = ?";
1106
    
1107
    try
1108
    {
1109
      //check out DBConnection
1110
      conn=DBConnectionPool.getDBConnection("AccessControlList.getDataSetId");
1111
      serialNumber=conn.getCheckOutSerialNumber();
1112
      
1113
      pStmt=conn.prepareStatement(query);
1114
      //bind the value to query
1115
      pStmt.setString(1, accessDocId);
1116
      pStmt.setString(2, accessDocId);
1117
      //execute the query
1118
      pStmt.execute();
1119
      rs=pStmt.getResultSet();
1120
      //process the result
1121
      if (rs.next()) //There are some records for the data set id for access id
1122
      {
1123
        dataSetId=rs.getString(1);
1124
      }
1125
      else //No data set id for the given access id in xml_relation table
1126
      {
1127
        dataSetId=null;
1128
      }
1129
    }//try
1130
    finally
1131
    {
1132
      try
1133
      {
1134
        pStmt.close();
1135
      }
1136
      finally
1137
      {
1138
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1139
      }
1140
    }
1141
    return dataSetId;
1142
  }//getDataPackageId() 
1143
  
1144
  /**
1145
    * Check from db connection if at least one of the list of @principals
1146
    * has @permission on @docid.
1147
    * @param permission permission type to check for
1148
    * @param principals list of names of principals to check for @permission
1149
    * @param docid document identifier to check on
1150
    */
1151
  public static boolean hasPermission(String permission, String user,
1152
                               String[] groups, String docId )
1153
                 throws SQLException, Exception
1154
  {
1155
    //detele the rev number if docid contains it
1156
    docId=MetaCatUtil.getDocIdFromString(docId);
1157
    boolean hasPermission=false;
1158
    String [] userPackage=null;
1159
    //for the commnad line invocation
1160
    if ((user==null) && (groups==null || groups.length==0))
1161
    {
1162
      return true;
1163
    }
1164
   
1165
    //create a userpackage including user, public and group member
1166
    userPackage=createUsersPackage(user, groups);
1167
    
1168
    //if the requested document is access documents and requested permission
1169
    //is "write", the user should have "all" right
1170
    if (isAccessDocument(docId) && (intValue(permission)==WRITE))
1171
    {
1172
      hasPermission = hasPermission(userPackage,docId, "ALL");
1173
    }//if
1174
    else //in other situation, just check the request permission
1175
    {
1176
    
1177
      // Check for @permission on @docid for @user and/or @groups
1178
      hasPermission = hasPermission(userPackage,docId, permission);
1179
     
1180
    }//else
1181
    
1182
    return hasPermission;
1183
  }
1184
 
1185
  /**
1186
    * Check from db connection if the users in String array @principals has
1187
    * @permission on @docid* 
1188
    * @param principals, names in userPakcage need to check for @permission
1189
    * @param docid, document identifier to check on
1190
    * @param permission, permission (write or all...) to check for 
1191
    */
1192
  private static boolean hasPermission(String [] principals, String docId,
1193
                                            String permission)
1194
                         throws SQLException
1195
  {
1196
    try 
1197
    {
1198
      //first, if there is a docid owner in user package, return true
1199
      //because doc owner has all permssion 
1200
      if (containDocumentOwner(principals, docId))
1201
      {
1202
          
1203
          return true;
1204
      }
1205
      
1206
      //If there is no owner in user package, checking the table
1207
      //check perm_order
1208
      if (isAllowFirst(principals, docId))
1209
      {
1210
        
1211
        if (hasExplicitDenyRule(principals, docId, permission))
1212
        {
1213
          //if it is allowfirst and has deny rule(either explicit )
1214
          //deny access
1215
          return false;
1216
        }//if
1217
        else if ( hasAllowRule(principals, docId, permission))
1218
        {
1219
          //if it is allowfirst and hasn't deny rule and has allow rule
1220
          //allow access
1221
          return true;
1222
        }//else if
1223
        else
1224
        {
1225
          //other situation deny access
1226
          return false;
1227
        }//else
1228
     }//if isAllowFirst
1229
     else //denyFirst
1230
     {
1231
       if (hasAllowRule(principals, docId, permission))
1232
       {
1233
         //if it is denyFirst and has allow rule, allow access
1234
         return true;
1235
       }
1236
       else
1237
       {
1238
         //if it is denyfirst but no allow rule, deny access
1239
         return false;
1240
       }
1241
     }//else denyfirst
1242
    }//try
1243
    catch (Exception e)
1244
    {
1245
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
1246
                         +e.getMessage(), 50);
1247
    }
1248
   
1249
    return false;
1250
  }//hasPermission
1251
 
1252

  
1253
 
1254
 
1255
  /**
1256 650
    * Get Access Control List information for document from db connetion.
1257 651
    * User or Group should have permissions for reading
1258 652
    * access control information for a document specified by @docid.
......
1337 731
        if ( !isOwned ) {
1338 732
          if ( !acfid.equals(acfid_prev) ) {
1339 733
            acfid_prev = acfid;
1340
            hasPermission = this.hasPermission("READ",user,groups,acfid);
734
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
735
             PermissionController controller = new PermissionController(acfid);
736
             hasPermission = controller.hasPermission(user,groups,
737
                                            AccessControlInterface.READSTRING);
1341 738
          }
1342 739
          if ( !hasPermission ) {
1343 740
            rs.next();

Also available in: Unified diff