Index: src/edu/ucsb/nceas/metacat/dataone/CNodeService.java
===================================================================
--- src/edu/ucsb/nceas/metacat/dataone/CNodeService.java	(revision 6643)
+++ src/edu/ucsb/nceas/metacat/dataone/CNodeService.java	(revision 6644)
@@ -37,6 +37,7 @@
 import org.apache.log4j.Logger;
 import org.dataone.client.CNode;
 import org.dataone.client.D1Client;
+import org.dataone.client.auth.CertificateManager;
 import org.dataone.service.cn.v1.CNAuthorization;
 import org.dataone.service.cn.v1.CNCore;
 import org.dataone.service.cn.v1.CNRead;
@@ -166,16 +167,16 @@
       try {
         systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
         systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
-	      HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
-	      HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
-	      
+        HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
+        HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
+        
       } catch (Exception e) {
-		      throw new ServiceFailure("4882", e.getMessage());
-		  
-	    } finally {
-	        HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
-	        
-	    }
+          throw new ServiceFailure("4882", e.getMessage());
+      
+      } finally {
+          HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
+          
+      }
     
       return true;
   }
@@ -199,68 +200,107 @@
    */
   @Override
   public boolean setReplicationStatus(Session session, Identifier pid,
-    NodeReference targetNode, ReplicationStatus status, long serialVersion) 
-    throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
-    InvalidRequest, NotFound {
+      NodeReference targetNode, ReplicationStatus status, long serialVersion) 
+      throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
+      InvalidRequest, NotFound {
+      
+      boolean allowed = false;
+      int replicaEntryIndex = -1;
+      List<Replica> replicas = null;
+      // get the subject
+      Subject subject = session.getSubject();
+      
+      SystemMetadata systemMetadata = null;
+      try {      
+          HazelcastService.getInstance().getSystemMetadataMap().lock(pid);
+          systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
+          
+          replicas = systemMetadata.getReplicaList();
+          int count = 0;
+          
+          // find the target replica index in the replica list
+          for (Replica replica: replicas) {
+              if (replica.getReplicaMemberNode().getValue().equals(targetNode.getValue())) {
+                  replicaEntryIndex = count;
+                  break;
+              }
+              count++;
+              
+          }
 
-    // get the subject
-    Subject subject = session.getSubject();
-    
-    // are we allowed to do this?
-    if (!isAuthorized(session, pid, Permission.WRITE)) {
-      throw new NotAuthorized("4720", Permission.WRITE + " not allowed by " + 
-          subject.getValue() + " on " + pid.getValue());  
-    }
-    
-    SystemMetadata systemMetadata = null;
-    try {      
-        HazelcastService.getInstance().getSystemMetadataMap().lock(pid);
-        systemMetadata = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
+          // are we allowed to do this? only CNs and target MNs are allowed
+          CNode cn = D1Client.getCN();
+          List<Node> nodes = cn.listNodes().getNodeList();
+          
+          // find the node in the node list
+          for ( Node node : nodes ) {
+              
+              NodeReference nodeReference = node.getIdentifier();
+              logMetacat.debug("In setReplicationStatus(), Node reference is: " + nodeReference.getValue());
+              
+              // allow target MN certs and CN certs
+              if (targetNode.getValue().equals(nodeReference.getValue()) ||
+                  node.getType() == NodeType.CN) {
+                  List<Subject> nodeSubjects = node.getSubjectList();
+                  
+                  // check if the session subject is in the node subject list
+                  for (Subject nodeSubject : nodeSubjects) {
+                      if ( CertificateManager.getInstance().equalsDN(
+                              nodeSubject.getValue(), subject.getValue()) ) {
+                          allowed = true; // subject of session == target node subject
+                          break;
+                          
+                      }
+                  }                 
+              }
+          }
 
-
-        // does the request have the most current system metadata?
-        if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
-           String msg = "The requested system metadata version number " + 
-               serialVersion + "differs from the current version at " +
-               systemMetadata.getSerialVersion().longValue() +
-               " Please get the latest copy in order to modify it.";
-           throw new InvalidRequest("4730", msg);
-        }
+          if ( !allowed ) {
+              String msg = "The subject identified by " + subject.getValue() +
+                " does not have permission to set the replication status for " +
+                "the replica identified by " + targetNode.getValue() + ".";
+              logMetacat.info(msg);
+              throw new NotAuthorized("4720", msg);
+              
+          }
+          
+          // does the request have the most current system metadata?
+          if ( systemMetadata.getSerialVersion().longValue() != serialVersion ) {
+             String msg = "The requested system metadata version number " + 
+                 serialVersion + "differs from the current version at " +
+                 systemMetadata.getSerialVersion().longValue() +
+                 " Please get the latest copy in order to modify it.";
+             throw new InvalidRequest("4730", msg);
+          }
+          
+      } catch (Exception e) { // Catch is generic since HZ throws RuntimeException
+        throw new NotFound("4740", "No record found for: " + pid.getValue() +
+            " : " + e.getMessage());
         
-    } catch (Exception e) { // Catch is generic since HZ throws RuntimeException
-      throw new NotFound("4740", "No record found for: " + pid.getValue() +
-          " : " + e.getMessage());
+      }
+          
+      // set the status for the replica
+      if ( replicaEntryIndex != -1 ) {          
+          replicas.get(replicaEntryIndex).setReplicationStatus(status);
+          
+      }
+            
+      // update the metadata
+      try {
+          systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
+          systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
+          HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
+          HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
+        
+      } catch (Exception e) {
+          throw new ServiceFailure("4700", e.getMessage());
       
-    }
-        
-    // set the status for the replica
-    List<Replica> replicas = systemMetadata.getReplicaList();
-    for (Replica replica: replicas) {
-        if (replica.getReplicaMemberNode().getValue().equals(targetNode.getValue())) {
-            replica.setReplicationStatus(status);
-            
-        }
-    }
-    
-    // [re]set the list -- redundant?
-    systemMetadata.setReplicaList(replicas);
-    
-    // update the metadata
-    try {
-        systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
-        systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
-	      HazelcastService.getInstance().getSystemMetadataMap().put(systemMetadata.getIdentifier(), systemMetadata);
-	      HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
-	    
-    } catch (Exception e) {
-		    throw new ServiceFailure("4700", e.getMessage());
-		
-	  } finally {
-	      HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
-	      
-	  }
-	
-    return true;
+      } finally {
+          HazelcastService.getInstance().getSystemMetadataMap().unlock(systemMetadata.getIdentifier());
+          
+      }
+      
+      return true;
   }
 
   /**
@@ -615,7 +655,7 @@
           HazelcastService.getInstance().getSystemMetadataMap().unlock(sysmeta.getIdentifier());
           
       } catch (Exception e) {
-      	logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
+        logMetacat.error("Problem registering system metadata: " + pid.getValue(), e);
           throw new ServiceFailure("4862", "Error inserting system metadata: " + 
               e.getClass() + ": " + e.getMessage());
           
@@ -755,16 +795,16 @@
       try {
           systemMetadata.setSerialVersion(systemMetadata.getSerialVersion().add(BigInteger.ONE));
           systemMetadata.setDateSysMetadataModified(Calendar.getInstance().getTime());
-	        HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
-	        HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
-	        
+          HazelcastService.getInstance().getSystemMetadataMap().put(pid, systemMetadata);
+          HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
+          
       } catch (Exception e) {
-		  throw new ServiceFailure("4490", e.getMessage());
-		  
-	    } finally {
-	        HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
-	    }
+      throw new ServiceFailure("4490", e.getMessage());
       
+      } finally {
+          HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
+      }
+      
       return pid;
   }
 
@@ -792,29 +832,29 @@
     throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
     NotFound, InvalidRequest {
 
-	  boolean isAllowed = false;
-	  SystemMetadata sysmeta = null;
+    boolean isAllowed = false;
+    SystemMetadata sysmeta = null;
     NodeReference targetNode = null;
     
-	  try {
-	    // get the target node reference from the nodes list
-	    CNode cn = D1Client.getCN();
-	    List<Node> nodes = cn.listNodes().getNodeList();
+    try {
+      // get the target node reference from the nodes list
+      CNode cn = D1Client.getCN();
+      List<Node> nodes = cn.listNodes().getNodeList();
 
-	    for ( Node node : nodes ) {
-	        Subject nodeSubject = node.getSubject(0);
-	        if (nodeSubject.getValue().equals(targetNodeSubject)) {
-	            targetNode = node.getIdentifier();
-	            
-	        }
-	    }
-	    
+      for ( Node node : nodes ) {
+          Subject nodeSubject = node.getSubject(0);
+          if (nodeSubject.getValue().equals(targetNodeSubject)) {
+              targetNode = node.getIdentifier();
+              
+          }
+      }
+      
 
-	    //lock, get, and unlock the pid
-	    HazelcastService.getInstance().getSystemMetadataMap().lock(pid);
-	    sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
-	    List<Replica> replicaList = sysmeta.getReplicaList();
-	    
+      //lock, get, and unlock the pid
+      HazelcastService.getInstance().getSystemMetadataMap().lock(pid);
+      sysmeta = HazelcastService.getInstance().getSystemMetadataMap().get(pid);
+      List<Replica> replicaList = sysmeta.getReplicaList();
+      
       // find the replica with the status set to 'requested'
       for (Replica replica : replicaList) {
           ReplicationStatus status = replica.getReplicationStatus();
@@ -829,24 +869,24 @@
       
       HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
 
-	  } catch(RuntimeException e) {
-	      // Catch Hazelcast RuntimeExceptions
-	      throw new ServiceFailure("4872", 
-	          "RuntimeException: Couldn't determine if node is allowed: " + 
-	          e.getStackTrace().toString());
-	    
+    } catch(RuntimeException e) {
+        // Catch Hazelcast RuntimeExceptions
+        throw new ServiceFailure("4872", 
+            "RuntimeException: Couldn't determine if node is allowed: " + 
+            e.getStackTrace().toString());
+      
     } catch(Exception e) {
         throw new ServiceFailure("4872", 
                 "General Exception: Couldn't determine if node is allowed: " + 
                 e.getStackTrace().toString());
         
-	  } finally {
-	    // always unlock the pid
+    } finally {
+      // always unlock the pid
       HazelcastService.getInstance().getSystemMetadataMap().unlock(pid);
 
-	  }
-	    
-	  return isAllowed;
+    }
+      
+    return isAllowed;
     
   }
 
@@ -1097,14 +1137,14 @@
       
   }
   
-  	@Override
-  	public ObjectList listObjects(Session session, Date startTime, 
+    @Override
+    public ObjectList listObjects(Session session, Date startTime, 
             Date endTime, ObjectFormatIdentifier formatid, Boolean replicaStatus,
             Integer start, Integer count)
-			throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
-			ServiceFailure {
-  		
-  		ObjectList objectList = null;
+      throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
+      ServiceFailure {
+      
+      ObjectList objectList = null;
         try {
             objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, formatid, replicaStatus, start, count);
         } catch (Exception e) {
@@ -1112,5 +1152,5 @@
         }
 
         return objectList;
-	}
+  }
 }
