OPENDJ-1106 fractional-replication: adding entry on a replica as DM should not exit with RC 50
Code review: Matthew Swift
Regression caused by the fix for OPENDJ-948 unauthorized disclosure of directory contents.
The code was looking for the entry matching the DN we are adding which obviously was null here.
Since it was null, the code went on to wrongly check the following conditions: op.isInternalOperation() || op.isSynchronizationOperation() || op.isInnerOperation().
The correct fix was to avoid calling AccessControlHandler.canDiscloseInformation() where it did not make sense at all, when there was no info to protect yet.
LocalBackend*Operation.java:
Do not call the setResultCodeAndMessageNoInfoDisclosure() when we fail to grab a lock, because this is not disclosing any sensitive information at that point.
LocalBackendAddOperation.java:
Do not call the setResultCodeAndMessageNoInfoDisclosure() when we fail to grab a lock, because this is not disclosing any sensitive information at that point.
In lockParent(), reversed the exception to make the code easier to read.
LocalBackendModifyDNOperation.java:
Do not call the setResultCodeAndMessageNoInfoDisclosure() when we fail to grab a lock, because this is not disclosing any sensitive information at that point.
In newDirectoryException(), removed the entryDN parameter since now this method is always called with a non null entry.
AciHandler.java:
Code cleanup
| | |
| | | { |
| | | aciListenerMgr.finalizeListenerManager(); |
| | | AciEffectiveRights.finalizeOnShutdown(); |
| | | DirectoryServer |
| | | .deregisterSupportedControl(OID_GET_EFFECTIVE_RIGHTS); |
| | | DirectoryServer.deregisterSupportedControl(OID_GET_EFFECTIVE_RIGHTS); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | AttributeType attributeType = getAttributeType(baseName); |
| | | AttributeValue attributeValue = |
| | | AttributeValues.create(attributeType, operation |
| | | .getAssertionValue()); |
| | | AttributeValues.create(attributeType, operation.getAssertionValue()); |
| | | container.setCurrentAttributeType(attributeType); |
| | | container.setCurrentAttributeValue(attributeValue); |
| | | return isAllowed(container, operation); |
| | |
| | | */ |
| | | boolean accessAllowed(AciContainer container) |
| | | { |
| | | DN dn = container.getResourceEntry().getDN(); |
| | | DN dn = container.getResourceDN(); |
| | | // For ACI_WRITE_ADD and ACI_WRITE_DELETE set the ACI_WRITE |
| | | // right. |
| | | if (container.hasRights(ACI_WRITE_ADD) |
| | |
| | | // type are being replaced or deleted. If only a subset is being |
| | | // deleted than this access check is skipped. |
| | | ModificationType modType = m.getModificationType(); |
| | | if (((modType == ModificationType.DELETE) && modAttr.isEmpty()) |
| | | || ((modType == ModificationType.REPLACE) |
| | | || (modType == ModificationType.INCREMENT))) |
| | | if ((modType == ModificationType.DELETE && modAttr.isEmpty()) |
| | | || modType == ModificationType.REPLACE |
| | | || modType == ModificationType.INCREMENT) |
| | | { |
| | | /* |
| | | * Check if we have rights to delete all values of an attribute |
| | |
| | | { |
| | | container.setCurrentAttributeType(modAttrType); |
| | | List<Attribute> attrList = |
| | | resourceEntry.getAttribute(modAttrType, modAttr |
| | | .getOptions()); |
| | | resourceEntry.getAttribute(modAttrType, modAttr.getOptions()); |
| | | if (attrList != null) |
| | | { |
| | | for (Attribute a : attrList) |
| | |
| | | case INCREMENT: |
| | | Entry modifiedEntry = operation.getModifiedEntry(); |
| | | List<Attribute> modifiedAttrs = |
| | | modifiedEntry.getAttribute(modAttrType, modAttr |
| | | .getOptions()); |
| | | modifiedEntry.getAttribute(modAttrType, modAttr.getOptions()); |
| | | if (modifiedAttrs != null) |
| | | { |
| | | for (Attribute attr : modifiedAttrs) |
| | |
| | | if (globalAcis != null) |
| | | { |
| | | aciList.addAci(DN.nullDN(), globalAcis); |
| | | Message message = |
| | | INFO_ACI_ADD_LIST_GLOBAL_ACIS.get(Integer |
| | | .toString(globalAcis.size())); |
| | | logError(message); |
| | | logError(INFO_ACI_ADD_LIST_GLOBAL_ACIS.get( |
| | | Integer.toString(globalAcis.size()))); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | Message message = |
| | | INFO_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI.get(String |
| | | .valueOf(configuration.dn())); |
| | | Message message = INFO_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI.get( |
| | | String.valueOf(configuration.dn())); |
| | | throw new InitializationException(message, e); |
| | | } |
| | | } |
| | |
| | | if (!operation.getClientConnection().hasPrivilege( |
| | | Privilege.MODIFY_ACL, operation)) |
| | | { |
| | | Message message = |
| | | INFO_ACI_ADD_FAILED_PRIVILEGE.get(String.valueOf(entry |
| | | .getDN()), String.valueOf(clientDN)); |
| | | Message message = INFO_ACI_ADD_FAILED_PRIVILEGE.get( |
| | | String.valueOf(entry.getDN()), String.valueOf(clientDN)); |
| | | logError(message); |
| | | return false; |
| | | } |
| | |
| | | } |
| | | catch (AciException ex) |
| | | { |
| | | Message message = |
| | | WARN_ACI_ADD_FAILED_DECODE.get(String.valueOf(entry |
| | | .getDN()), ex.getMessage()); |
| | | Message message = WARN_ACI_ADD_FAILED_DECODE.get( |
| | | String.valueOf(entry.getDN()), ex.getMessage()); |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); |
| | | } |
| | |
| | | entryLock = LockManager.lockWrite(entryDN); |
| | | if (entryLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(entryDN, ResultCode.BUSY, |
| | | ERR_ADD_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_ADD_CANNOT_LOCK_ENTRY.get( |
| | | String.valueOf(entryDN))); |
| | | return; |
| | | } |
| | | |
| | |
| | | provider.handleConflictResolution(this); |
| | | if (!result.continueProcessing()) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(entryDN, |
| | | result.getResultCode(), result.getErrorMessage()); |
| | | setResultCode(result.getResultCode()); |
| | | appendErrorMessage(result.getErrorMessage()); |
| | | setMatchedDN(result.getMatchedDN()); |
| | | setReferralURLs(result.getReferralURLs()); |
| | | return; |
| | |
| | | * @throws DirectoryException If a problem occurs while attempting to |
| | | * acquire the lock. |
| | | */ |
| | | private Lock lockParent(DN parentDN) |
| | | throws DirectoryException |
| | | private Lock lockParent(DN parentDN) throws DirectoryException |
| | | { |
| | | Lock parentLock = null; |
| | | |
| | | if (parentDN == null) |
| | | if (parentDN != null) |
| | | { |
| | | // Either this entry is a suffix or doesn't belong in the directory. |
| | | if (DirectoryServer.isNamingContext(entryDN)) |
| | | final Lock parentLock = LockManager.lockRead(parentDN); |
| | | if (parentLock == null) |
| | | { |
| | | // This is fine. This entry is one of the configured suffixes. |
| | | parentLock = null; |
| | | throw newDirectoryException(parentDN, ResultCode.BUSY, |
| | | ERR_ADD_CANNOT_LOCK_PARENT.get( |
| | | String.valueOf(entryDN), |
| | | String.valueOf(parentDN))); |
| | | } |
| | | else if (entryDN.isNullDN()) |
| | | { |
| | | // This is not fine. The root DSE cannot be added. |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_ADD_CANNOT_ADD_ROOT_DSE.get()); |
| | | } |
| | | else |
| | | { |
| | | // The entry doesn't have a parent but isn't a suffix. This is not |
| | | // allowed. |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | ERR_ADD_ENTRY_NOT_SUFFIX.get( |
| | | String.valueOf(entryDN))); |
| | | } |
| | | return parentLock; |
| | | } |
| | | |
| | | // Either this entry is a suffix or doesn't belong in the directory. |
| | | if (DirectoryServer.isNamingContext(entryDN)) |
| | | { |
| | | // This is fine. This entry is one of the configured suffixes. |
| | | return null; |
| | | } |
| | | else if (entryDN.isNullDN()) |
| | | { |
| | | // This is not fine. The root DSE cannot be added. |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, |
| | | ERR_ADD_CANNOT_ADD_ROOT_DSE.get()); |
| | | } |
| | | else |
| | | { |
| | | parentLock = LockManager.lockRead(parentDN); |
| | | if (parentLock == null) |
| | | { |
| | | throw newDirectoryException(entryDN, ResultCode.BUSY, |
| | | ERR_ADD_CANNOT_LOCK_PARENT.get( |
| | | String.valueOf(entryDN), |
| | | String.valueOf(parentDN))); |
| | | } |
| | | // The entry doesn't have a parent but isn't a suffix. This is not |
| | | // allowed. |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | ERR_ADD_ENTRY_NOT_SUFFIX.get(String.valueOf(entryDN))); |
| | | } |
| | | |
| | | return parentLock; |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | if (readLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(null, entryDN, ResultCode.BUSY, |
| | | ERR_COMPARE_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_COMPARE_CANNOT_LOCK_ENTRY.get( |
| | | String.valueOf(entryDN))); |
| | | return; |
| | | } |
| | | |
| | |
| | | try |
| | | { |
| | | entry = DirectoryServer.getEntry(entryDN); |
| | | |
| | | if (entry == null) |
| | | { |
| | | setResultCode(ResultCode.NO_SUCH_OBJECT); |
| | |
| | | { |
| | | if (entryLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(entry, ResultCode.BUSY, |
| | | ERR_DELETE_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_DELETE_CANNOT_LOCK_ENTRY.get( |
| | | String.valueOf(entryDN))); |
| | | return; |
| | | } |
| | | |
| | |
| | | { |
| | | if (currentLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(null, entryDN, ResultCode.BUSY, |
| | | ERR_MODDN_CANNOT_LOCK_CURRENT_DN.get(String.valueOf(entryDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_MODDN_CANNOT_LOCK_CURRENT_DN.get( |
| | | String.valueOf(entryDN))); |
| | | return; |
| | | } |
| | | |
| | |
| | | newLock = LockManager.lockWrite(newDN); |
| | | if (newLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(null, newDN, ResultCode.BUSY, |
| | | ERR_MODDN_CANNOT_LOCK_NEW_DN.get(String.valueOf(entryDN), String |
| | | .valueOf(newDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_MODDN_CANNOT_LOCK_NEW_DN.get( |
| | | String.valueOf(entryDN), String.valueOf(newDN))); |
| | | return; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | private DirectoryException newDirectoryException(Entry entry, DN entryDN, |
| | | private DirectoryException newDirectoryException(Entry entry, |
| | | ResultCode resultCode, Message message) throws DirectoryException |
| | | { |
| | | return LocalBackendWorkflowElement.newDirectoryException(this, entry, |
| | | entryDN, resultCode, message, ResultCode.NO_SUCH_OBJECT, |
| | | return LocalBackendWorkflowElement.newDirectoryException(this, entry, null, |
| | | resultCode, message, ResultCode.NO_SUCH_OBJECT, |
| | | ERR_MODDN_NO_CURRENT_ENTRY.get(String.valueOf(entryDN))); |
| | | } |
| | | |
| | |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | |
| | | throw newDirectoryException(currentEntry, entryDN, |
| | | de.getResultCode(), |
| | | throw newDirectoryException(currentEntry, de.getResultCode(), |
| | | ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get( |
| | | String.valueOf(entryDN), |
| | | de.getMessageObject())); |
| | |
| | | { |
| | | if (!filter.matchesEntry(currentEntry)) |
| | | { |
| | | throw newDirectoryException(currentEntry, entryDN, |
| | | throw newDirectoryException(currentEntry, |
| | | ResultCode.ASSERTION_FAILED, |
| | | ERR_MODDN_ASSERTION_FAILED.get(String |
| | | .valueOf(entryDN))); |
| | |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | |
| | | throw newDirectoryException(currentEntry, entryDN, |
| | | de.getResultCode(), |
| | | throw newDirectoryException(currentEntry, de.getResultCode(), |
| | | ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get( |
| | | String.valueOf(entryDN), |
| | | de.getMessageObject())); |
| | |
| | | { |
| | | if (entryLock == null) |
| | | { |
| | | setResultCodeAndMessageNoInfoDisclosure(currentEntry, ResultCode.BUSY, |
| | | ERR_MODIFY_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN))); |
| | | setResultCode(ResultCode.BUSY); |
| | | appendErrorMessage(ERR_MODIFY_CANNOT_LOCK_ENTRY.get( |
| | | String.valueOf(entryDN))); |
| | | return; |
| | | } |
| | | |