Project

General

Profile

« Previous | Next » 

Revision 9190

Added by Jing Tao over 9 years ago

Refactory the authorize methods on D1NodeService.
Add the check for whom can call mn.updatesystemMetadata.

View differences:

src/edu/ucsb/nceas/metacat/dataone/D1NodeService.java
879 879
   * 
880 880
   * @param session - the Session object containing the credentials for the Subject
881 881
   * 
882
   * @return true if the user is admin
882
   * @return true if the user is admin (mn itself or a cn )
883 883
   * 
884 884
   * @throws ServiceFailure
885 885
   * @throws InvalidToken
......
907 907
      
908 908
      // check the CN list
909 909
      if (!allowed) {
910
	      List<Node> nodes = null;
910
	      allowed = isCNAdmin(session);
911
      }
912
      
913
      return allowed;
914
  }
915
  
916
  /*
917
   * Determine if the specified session is a CN or not. Return true if it is; otherwise false.
918
   */
919
  protected boolean isCNAdmin (Session session) {
920
      boolean allowed = false;
921
      List<Node> nodes = null;
911 922

  
912
    	  try {
913
		      // are we allowed to do this? only CNs are allowed
914
		      CNode cn = D1Client.getCN();
915
		      nodes = cn.listNodes().getNodeList();
916
    	  }
917
	      catch (Throwable e) {
918
	    	  logMetacat.warn(e.getMessage());
919
	    	  return false;  
920
	      }
921
		      
922
	      if ( nodes == null ) {
923
	    	  return false;
924
	          //throw new ServiceFailure("4852", "Couldn't get node list.");
925
	      }
926
	      
927
	      // find the node in the node list
928
	      for ( Node node : nodes ) {
929
	          
930
	          NodeReference nodeReference = node.getIdentifier();
931
	          logMetacat.debug("In isAdminAuthorized(), Node reference is: " + nodeReference.getValue());
932
	          
933
	          Subject subject = session.getSubject();
934
	          
935
	          if (node.getType() == NodeType.CN) {
936
	              List<Subject> nodeSubjects = node.getSubjectList();
937
	              
938
	              // check if the session subject is in the node subject list
939
	              for (Subject nodeSubject : nodeSubjects) {
940
	                  logMetacat.debug("In isAdminAuthorized(), comparing subjects: " +
941
	                      nodeSubject.getValue() + " and " + subject.getValue());
942
	                  if ( nodeSubject.equals(subject) ) {
943
	                      allowed = true; // subject of session == target node subject
944
	                      break;
945
	                      
946
	                  }
947
	              }              
948
	          }
949
	      }
923
      try {
924
          // are we allowed to do this? only CNs are allowed
925
          CNode cn = D1Client.getCN();
926
          nodes = cn.listNodes().getNodeList();
950 927
      }
928
      catch (Throwable e) {
929
          logMetacat.warn(e.getMessage());
930
          return false;  
931
      }
932
          
933
      if ( nodes == null ) {
934
          return false;
935
          //throw new ServiceFailure("4852", "Couldn't get node list.");
936
      }
951 937
      
938
      // find the node in the node list
939
      for ( Node node : nodes ) {
940
          
941
          NodeReference nodeReference = node.getIdentifier();
942
          logMetacat.debug("In isAdminAuthorized(), Node reference is: " + nodeReference.getValue());
943
          
944
          Subject subject = session.getSubject();
945
          
946
          if (node.getType() == NodeType.CN) {
947
              List<Subject> nodeSubjects = node.getSubjectList();
948
              
949
              // check if the session subject is in the node subject list
950
              for (Subject nodeSubject : nodeSubjects) {
951
                  logMetacat.debug("In isAdminAuthorized(), comparing subjects: " +
952
                      nodeSubject.getValue() + " and " + subject.getValue());
953
                  if ( nodeSubject.equals(subject) ) {
954
                      allowed = true; // subject of session == target node subject
955
                      break;
956
                      
957
                  }
958
              }              
959
          }
960
      }
952 961
      return allowed;
953 962
  }
954 963
  
......
1030 1039
    	throw new InvalidRequest("1761", "Permission was not provided or is invalid");
1031 1040
    }
1032 1041
    
1033
    // permissions are hierarchical
1034
    List<Permission> expandedPermissions = null;
1035
    
1036 1042
    // always allow CN access
1037 1043
    if ( isAdminAuthorized(session) ) {
1038 1044
        allowed = true;
......
1052 1058
        return allowed;
1053 1059
    }
1054 1060
    
1055
    // get the subject[s] from the session
1056
	//defer to the shared util for recursively compiling the subjects	
1057
	Set<Subject> subjects = AuthUtils.authorizedClientSubjects(session);
1061
    //is it the owner of the object or the access rules allow the user?
1062
    allowed = userHasPermission(session,  pid, permission );
1058 1063
    
1059
	// track the identities we have checked against
1060
	StringBuffer includedSubjects = new StringBuffer();
1061
    	
1062
    // get the system metadata
1063
    String pidStr = pid.getValue();
1064
    SystemMetadata systemMetadata = null;
1065
    try {
1066
        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1067

  
1068
    } catch (Exception e) {
1069
        // convert Hazelcast RuntimeException to NotFound
1070
        logMetacat.error("An error occurred while getting system metadata for identifier " +
1071
            pid.getValue() + ". The error message was: " + e.getMessage());
1072
        throw new NotFound("1800", "No record found for " + pidStr);
1073
        
1074
    } 
1075
    
1076
    // throw not found if it was not found
1077
    if (systemMetadata == null) {
1078
        String localId = null;
1079
        String error = "No system metadata could be found for given PID: " + pidStr;
1080
        try {
1081
            localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1082
          
1083
         } catch (Exception e) {
1084
            logMetacat.warn("Couldn't find the local id for the pid "+pidStr);
1085
        }
1086
        
1087
        if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1088
            error = error + ". "+DELETEDMESSAGE;
1089
        } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1090
            error = error + ". "+DELETEDMESSAGE;
1091
        }
1092
        throw new NotFound("1800", error);
1093
    }
1094
	    
1095
    // do we own it?
1096
    for (Subject s: subjects) {
1097
      logMetacat.debug("Comparing \t" + 
1098
                       systemMetadata.getRightsHolder().getValue() +
1099
                       " \tagainst \t" + s.getValue());
1100
      	includedSubjects.append(s.getValue() + "; ");
1101
    	allowed = systemMetadata.getRightsHolder().equals(s);
1102
    	if (allowed) {
1103
    		return allowed;
1104
    	}
1105
    }    
1106
    
1107
    // otherwise check the access rules
1108
    try {
1109
	    List<AccessRule> allows = systemMetadata.getAccessPolicy().getAllowList();
1110
	    search: // label break
1111
	    for (AccessRule accessRule: allows) {
1112
	      for (Subject s: subjects) {
1113
	        logMetacat.debug("Checking allow access rule for subject: " + s.getValue());
1114
	        if (accessRule.getSubjectList().contains(s)) {
1115
	        	logMetacat.debug("Access rule contains subject: " + s.getValue());
1116
	        	for (Permission p: accessRule.getPermissionList()) {
1117
		        	logMetacat.debug("Checking permission: " + p.xmlValue());
1118
	        		expandedPermissions = expandPermissions(p);
1119
	        		allowed = expandedPermissions.contains(permission);
1120
	        		if (allowed) {
1121
			        	logMetacat.info("Permission granted: " + p.xmlValue() + " to " + s.getValue());
1122
	        			break search; //label break
1123
	        		}
1124
	        	}
1125
        		
1126
	        }
1127
	      }
1128
	    }
1129
    } catch (Exception e) {
1130
    	// catch all for errors - safe side should be to deny the access
1131
    	logMetacat.error("Problem checking authorization - defaulting to deny", e);
1132
		allowed = false;
1133
	  
1134
    }
1135
    
1136 1064
    // throw or return?
1137 1065
    if (!allowed) {
1138
      throw new NotAuthorized("1820", permission + " not allowed on " + pidStr + " for subject[s]: " + includedSubjects.toString() );
1066
     // track the identities we have checked against
1067
      StringBuffer includedSubjects = new StringBuffer();
1068
      Set<Subject> subjects = AuthUtils.authorizedClientSubjects(session);
1069
      for (Subject s: subjects) {
1070
             includedSubjects.append(s.getValue() + "; ");
1071
        }    
1072
      throw new NotAuthorized("1820", permission + " not allowed on " + pid.getValue() + " for subject[s]: " + includedSubjects.toString() );
1139 1073
    }
1140 1074
    
1141 1075
    return allowed;
1142 1076
    
1143 1077
  }
1144 1078
  
1079
  
1145 1080
  /*
1081
   * Determine if a user has the permission to perform the specified permission.
1082
   * 1. Owner can have any permission.
1083
   * 2. Access table allow the user has the permission
1084
   */
1085
  protected boolean userHasPermission(Session userSession, Identifier pid, Permission permission ) throws NotFound{
1086
      boolean allowed = false;
1087
      // permissions are hierarchical
1088
      List<Permission> expandedPermissions = null;
1089
      // get the subject[s] from the session
1090
      //defer to the shared util for recursively compiling the subjects   
1091
      Set<Subject> subjects = AuthUtils.authorizedClientSubjects(userSession);
1092
          
1093
      // get the system metadata
1094
      String pidStr = pid.getValue();
1095
      SystemMetadata systemMetadata = null;
1096
      try {
1097
          systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1098

  
1099
      } catch (Exception e) {
1100
          // convert Hazelcast RuntimeException to NotFound
1101
          logMetacat.error("An error occurred while getting system metadata for identifier " +
1102
              pid.getValue() + ". The error message was: " + e.getMessage());
1103
          throw new NotFound("1800", "No record found for " + pidStr);
1104
          
1105
      } 
1106
      
1107
      // throw not found if it was not found
1108
      if (systemMetadata == null) {
1109
          String localId = null;
1110
          String error = "No system metadata could be found for given PID: " + pidStr;
1111
          try {
1112
              localId = IdentifierManager.getInstance().getLocalId(pid.getValue());
1113
            
1114
           } catch (Exception e) {
1115
              logMetacat.warn("Couldn't find the local id for the pid "+pidStr);
1116
          }
1117
          
1118
          if(localId != null && EventLog.getInstance().isDeleted(localId)) {
1119
              error = error + ". "+DELETEDMESSAGE;
1120
          } else if (localId == null && EventLog.getInstance().isDeleted(pid.getValue())) {
1121
              error = error + ". "+DELETEDMESSAGE;
1122
          }
1123
          throw new NotFound("1800", error);
1124
      }
1125
          
1126
      // do we own it?
1127
      for (Subject s: subjects) {
1128
        logMetacat.debug("Comparing \t" + 
1129
                         systemMetadata.getRightsHolder().getValue() +
1130
                         " \tagainst \t" + s.getValue());
1131
          //includedSubjects.append(s.getValue() + "; ");
1132
          allowed = systemMetadata.getRightsHolder().equals(s);
1133
          if (allowed) {
1134
              return allowed;
1135
          }
1136
      }    
1137
      
1138
      // otherwise check the access rules
1139
      try {
1140
          List<AccessRule> allows = systemMetadata.getAccessPolicy().getAllowList();
1141
          search: // label break
1142
          for (AccessRule accessRule: allows) {
1143
            for (Subject s: subjects) {
1144
              logMetacat.debug("Checking allow access rule for subject: " + s.getValue());
1145
              if (accessRule.getSubjectList().contains(s)) {
1146
                  logMetacat.debug("Access rule contains subject: " + s.getValue());
1147
                  for (Permission p: accessRule.getPermissionList()) {
1148
                      logMetacat.debug("Checking permission: " + p.xmlValue());
1149
                      expandedPermissions = expandPermissions(p);
1150
                      allowed = expandedPermissions.contains(permission);
1151
                      if (allowed) {
1152
                          logMetacat.info("Permission granted: " + p.xmlValue() + " to " + s.getValue());
1153
                          break search; //label break
1154
                      }
1155
                  }
1156
                  
1157
              }
1158
            }
1159
          }
1160
      } catch (Exception e) {
1161
          // catch all for errors - safe side should be to deny the access
1162
          logMetacat.error("Problem checking authorization - defaulting to deny", e);
1163
          allowed = false;
1164
        
1165
      }
1166
      return allowed;
1167
  }
1168
  /*
1146 1169
   * parse a logEntry and get the relevant field from it
1147 1170
   * 
1148 1171
   * @param fieldname
......
1514 1537

  
1515 1538
    }
1516 1539
    
1540
    /**
1541
     * Update the system metadata of the specified pid
1542
     * @param session - the identity of the client which calls the method
1543
     * @param pid - the identifier of the object which will be updated
1544
     * @param sysmeta - the new system metadata  
1545
     * @return
1546
     * @throws NotImplemented
1547
     * @throws NotAuthorized
1548
     * @throws ServiceFailure
1549
     * @throws InvalidRequest
1550
     * @throws InvalidSystemMetadata
1551
     * @throws InvalidToken
1552
     */
1517 1553
	public boolean updateSystemMetadata(Session session, Identifier pid,
1518 1554
			SystemMetadata sysmeta) throws NotImplemented, NotAuthorized,
1519 1555
			ServiceFailure, InvalidRequest, InvalidSystemMetadata, InvalidToken {
1520 1556
		
1521 1557
		// The lock to be used for this identifier
1522 1558
      Lock lock = null;
1523
      if(pid == null || pid.getValue() == null) {
1524
          throw new InvalidRequest("4863", "Please specify the id in the updateSystemMetadata request ") ;
1525
      }
1526

  
1527
      // TODO: control who can call this?
1528
      if (session == null) {
1529
          //TODO: many of the thrown exceptions do not use the correct error codes
1530
          //check these against the docs and correct them
1531
          throw new NotAuthorized("4861", "No Session - could not authorize for updating system metadata." +
1532
                  "  If you are not logged in, please do so and retry the request.");
1533
      } else {
1534
          try {
1535
              boolean allow = isAuthorized(session, pid, Permission.CHANGE_PERMISSION);
1536
              if(!allow) {
1537
                  throw new NotAuthorized("4861", "The client -"+ session.getSubject().getValue()+ "is not authorized for updating the system metadata of the object "+pid.getValue());
1538
              }
1539
          } catch (NotFound e) {
1540
              throw new InvalidRequest("4863", "Can't determine if the client has the permission to update the system metacat of the object with id "+pid.getValue()+" since "+e.getDescription());
1541
          }
1542
          
1543
      }
1544
      
1559
     
1545 1560
      // verify that guid == SystemMetadata.getIdentifier()
1546 1561
      logMetacat.debug("Comparing guid|sysmeta_guid: " + pid.getValue() + 
1547 1562
          "|" + sysmeta.getIdentifier().getValue());
......
1600 1615
      return true;
1601 1616
	}
1602 1617
	
1603
	/*
1604
	 * Determine if the current node is the authoritative node for the given pid.
1605
	 */
1606
	protected boolean isAuthoritativeNode(Identifier pid) {
1607
	    boolean isAuthoritativeNode = false;
1608
	    if(pid != null && pid.getValue() != null) {
1609
	        SystemMetadata sys = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
1610
	        if(sys != null) {
1611
	            NodeReference node = sys.getAuthoritativeMemberNode();
1612
	            if(node != null) {
1613
	                String nodeValue = node.getValue();
1614
	                logMetacat.debug("The authoritative node for id "+pid.getValue()+" is "+nodeValue);
1615
	                //System.out.println("The authoritative node for id "+pid.getValue()+" is "+nodeValue);
1616
	                String currentNodeId = Settings.getConfiguration().getString("dataone.nodeId");
1617
	                logMetacat.debug("The node id in metacat.properties is "+currentNodeId);
1618
	                //System.out.println("The node id in metacat.properties is "+currentNodeId);
1619
	                if(currentNodeId != null && !currentNodeId.trim().equals("") && currentNodeId.equals(nodeValue)) {
1620
	                    logMetacat.debug("They are matching");
1621
	                    //System.out.println("They are matching");
1622
	                    isAuthoritativeNode = true;
1623
	                }
1624
	            }
1625
	        }
1626
	    }
1627
	    return isAuthoritativeNode;
1628
	}
1629 1618
	
1630 1619
	/*
1631 1620
	 * Check if the newMeta modifies an immutable field. 
src/edu/ucsb/nceas/metacat/dataone/MNodeService.java
2141 2141
		
2142 2142
		return bagInputStream;
2143 2143
	}
2144

  
2144
    
2145
	/**
2146
	 * Update the system metadata of the specified pid.
2147
	 */
2145 2148
	@Override
2146 2149
	public boolean updateSystemMetadata(Session session, Identifier pid,
2147 2150
            SystemMetadata sysmeta) throws NotImplemented, NotAuthorized,
......
2149 2152
	 if(sysmeta == null) {
2150 2153
	     throw  new InvalidRequest("4863", "The system metadata object should NOT be null in the updateSystemMetadata request.");
2151 2154
	 }
2155
	 if(pid == null || pid.getValue() == null) {
2156
         throw new InvalidRequest("4863", "Please specify the id in the updateSystemMetadata request ") ;
2157
     }
2158

  
2152 2159
	 if(!isAuthoritativeNode(pid)) {
2153 2160
	     throw  new InvalidRequest("4863", "Client can only call updateSystemMetadata request on the authoritative memember node.");
2154 2161
	 }
2162

  
2163
     if (session == null) {
2164
         //TODO: many of the thrown exceptions do not use the correct error codes
2165
         //check these against the docs and correct them
2166
         throw new NotAuthorized("4861", "No Session - could not authorize for updating system metadata." +
2167
                 "  If you are not logged in, please do so and retry the request.");
2168
     } else {
2169
         try {
2170
             //Following session can do the change:
2171
           //- Authoritative Member Node (we can use isNodeAdmin since we checked isAuthoritativeNode in line 2159)
2172
             //- Owner of object (coved by the userHasPermission method)
2173
             //- user subjects with the change permission
2174
             //Note: Coordinating Node can not because MN is authoritative
2175
             if(!isNodeAdmin(session) && !userHasPermission(session, pid, Permission.CHANGE_PERMISSION)) {
2176
                 throw new NotAuthorized("4861", "The client -"+ session.getSubject().getValue()+ "is not authorized for updating the system metadata of the object "+pid.getValue());
2177
             }
2178
         } catch (NotFound e) {
2179
             throw new InvalidRequest("4863", "Can't determine if the client has the permission to update the system metacat of the object with id "+pid.getValue()+" since "+e.getDescription());
2180
         }
2181
         
2182
     }
2155 2183
      //update the system metadata locally  
2156 2184
      boolean success = super.updateSystemMetadata(session, pid, sysmeta);
2157 2185
      
2158 2186
      if(success) {
2187
          //TODO
2159 2188
          //notify the cns the synchornize the new system metadata.
2160 2189
      }
2161 2190
      return success;
2162 2191
    }
2192
	
2193
	/*
2194
     * Determine if the current node is the authoritative node for the given pid.
2195
     */
2196
    protected boolean isAuthoritativeNode(Identifier pid) {
2197
        boolean isAuthoritativeNode = false;
2198
        if(pid != null && pid.getValue() != null) {
2199
            SystemMetadata sys = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
2200
            if(sys != null) {
2201
                NodeReference node = sys.getAuthoritativeMemberNode();
2202
                if(node != null) {
2203
                    String nodeValue = node.getValue();
2204
                    logMetacat.debug("The authoritative node for id "+pid.getValue()+" is "+nodeValue);
2205
                    //System.out.println("The authoritative node for id "+pid.getValue()+" is "+nodeValue);
2206
                    String currentNodeId = Settings.getConfiguration().getString("dataone.nodeId");
2207
                    logMetacat.debug("The node id in metacat.properties is "+currentNodeId);
2208
                    //System.out.println("The node id in metacat.properties is "+currentNodeId);
2209
                    if(currentNodeId != null && !currentNodeId.trim().equals("") && currentNodeId.equals(nodeValue)) {
2210
                        logMetacat.debug("They are matching");
2211
                        //System.out.println("They are matching");
2212
                        isAuthoritativeNode = true;
2213
                    }
2214
                }
2215
            }
2216
        }
2217
        return isAuthoritativeNode;
2218
    }
2163 2219
    
2164 2220
}

Also available in: Unified diff