Search in sources :

Example 1 with EntryValidator

use of com.unboundid.ldap.sdk.schema.EntryValidator in project ldapsdk by pingidentity.

the class InMemoryRequestHandler method processModifyDNRequest.

/**
 * Attempts to process the provided modify DN request.  The attempt will fail
 * if any of the following conditions is true:
 * <UL>
 *   <LI>There is a problem with any of the request controls.</LI>
 *   <LI>The modify DN request contains a malformed target DN, new RDN, or
 *       new superior DN.</LI>
 *   <LI>The original or new DN is that of the root DSE.</LI>
 *   <LI>The original or new DN is that of the subschema subentry.</LI>
 *   <LI>The new DN of the entry would conflict with the DN of an existing
 *       entry.</LI>
 *   <LI>The new DN of the entry would exist outside the set of defined
 *       base DNs.</LI>
 *   <LI>The new DN of the entry is not a defined base DN and does not exist
 *       immediately below an existing entry.</LI>
 * </UL>
 *
 * @param  messageID  The message ID of the LDAP message containing the modify
 *                    DN request.
 * @param  request    The modify DN request that was included in the LDAP
 *                    message that was received.
 * @param  controls   The set of controls included in the LDAP message.  It
 *                    may be empty if there were no controls, but will not be
 *                    {@code null}.
 *
 * @return  The {@link LDAPMessage} containing the response to send to the
 *          client.  The protocol op in the {@code LDAPMessage} must be an
 *          {@code ModifyDNResponseProtocolOp}.
 */
@Override()
@NotNull()
public LDAPMessage processModifyDNRequest(final int messageID, @NotNull final ModifyDNRequestProtocolOp request, @NotNull final List<Control> controls) {
    synchronized (entryMap) {
        // Sleep before processing, if appropriate.
        sleepBeforeProcessing();
        // Process the provided request controls.
        final Map<String, Control> controlMap;
        try {
            controlMap = RequestControlPreProcessor.processControls(LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST, controls);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        final ArrayList<Control> responseControls = new ArrayList<>(1);
        // If this operation type is not allowed, then reject it.
        final boolean isInternalOp = controlMap.containsKey(OID_INTERNAL_OPERATION_REQUEST_CONTROL);
        if ((!isInternalOp) && (!config.getAllowedOperationTypes().contains(OperationType.MODIFY_DN))) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MODIFY_DN_NOT_ALLOWED.get(), null));
        }
        // client is authenticated.
        if ((authenticatedDN.isNullDN() && config.getAuthenticationRequiredOperationTypes().contains(OperationType.MODIFY_DN))) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE, null, ERR_MEM_HANDLER_MODIFY_DN_REQUIRES_AUTH.get(), null));
        }
        // without actually doing any further processing.
        try {
            final ASN1OctetString txnID = processTransactionRequest(messageID, request, controlMap);
            if (txnID != null) {
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, INFO_MEM_HANDLER_OP_IN_TXN.get(txnID.stringValue()), null));
            }
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(le.getResultCode().intValue(), le.getMatchedDN(), le.getDiagnosticMessage(), StaticUtils.toList(le.getReferralURLs())), le.getResponseControls());
        }
        // Get the parsed target DN, new RDN, and new superior DN values.
        final DN dn;
        final Schema schema = schemaRef.get();
        try {
            dn = new DN(request.getDN(), schema);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_MALFORMED_DN.get(request.getDN(), le.getMessage()), null));
        }
        final RDN newRDN;
        try {
            newRDN = new RDN(request.getNewRDN(), schema);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_MALFORMED_NEW_RDN.get(request.getDN(), request.getNewRDN(), le.getMessage()), null));
        }
        final DN newSuperiorDN;
        final String newSuperiorString = request.getNewSuperiorDN();
        if (newSuperiorString == null) {
            newSuperiorDN = null;
        } else {
            try {
                newSuperiorDN = new DN(newSuperiorString, schema);
            } catch (final LDAPException le) {
                Debug.debugException(le);
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_MALFORMED_NEW_SUPERIOR.get(request.getDN(), request.getNewSuperiorDN(), le.getMessage()), null));
            }
        }
        // See if the target entry or one of its superiors is a smart referral.
        if (!controlMap.containsKey(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID)) {
            final Entry referralEntry = findNearestReferral(dn);
            if (referralEntry != null) {
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.REFERRAL_INT_VALUE, referralEntry.getDN(), INFO_MEM_HANDLER_REFERRAL_ENCOUNTERED.get(), getReferralURLs(dn, referralEntry)));
            }
        }
        // changelog entry.
        if (dn.isNullDN()) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_ROOT_DSE.get(), null));
        } else if (dn.equals(subschemaSubentryDN)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_SOURCE_IS_SCHEMA.get(), null));
        } else if (dn.isDescendantOf(changeLogBaseDN, true)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_SOURCE_IS_CHANGELOG.get(), null));
        }
        // Construct the new DN.
        final DN newDN;
        if (newSuperiorDN == null) {
            final DN originalParent = dn.getParent();
            if (originalParent == null) {
                newDN = new DN(newRDN);
            } else {
                newDN = new DN(newRDN, originalParent);
            }
        } else {
            newDN = new DN(newRDN, newSuperiorDN);
        }
        // If the new DN matches the old DN, then fail.
        if (newDN.equals(dn)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_NEW_DN_SAME_AS_OLD.get(request.getDN()), null));
        }
        // If the new DN is below a smart referral, then fail.
        if (!controlMap.containsKey(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID)) {
            final Entry referralEntry = findNearestReferral(newDN);
            if (referralEntry != null) {
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, referralEntry.getDN(), ERR_MEM_HANDLER_MOD_DN_NEW_DN_BELOW_REFERRAL.get(request.getDN(), referralEntry.getDN().toString(), newDN.toString()), null));
            }
        }
        // If the target entry doesn't exist, then fail.
        final Entry originalEntry = entryMap.get(dn);
        if (originalEntry == null) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), ERR_MEM_HANDLER_MOD_DN_NO_SUCH_ENTRY.get(request.getDN()), null));
        }
        // If the new DN matches the subschema subentry DN, then fail.
        if (newDN.equals(subschemaSubentryDN)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_TARGET_IS_SCHEMA.get(request.getDN(), newDN.toString()), null));
        }
        // If the new DN is at or below the changelog base DN, then fail.
        if (newDN.isDescendantOf(changeLogBaseDN, true)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_TARGET_IS_CHANGELOG.get(request.getDN(), newDN.toString()), null));
        }
        // If the new DN already exists, then fail.
        if (entryMap.containsKey(newDN)) {
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_TARGET_ALREADY_EXISTS.get(request.getDN(), newDN.toString()), null));
        }
        // fail.
        if (baseDNs.contains(newDN)) {
        // The modify DN can be processed.
        } else {
            final DN newParent = newDN.getParent();
            if ((newParent != null) && entryMap.containsKey(newParent)) {
            // The modify DN can be processed.
            } else {
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(newDN), ERR_MEM_HANDLER_MOD_DN_PARENT_DOESNT_EXIST.get(request.getDN(), newDN.toString()), null));
            }
        }
        // Create a copy of the entry and update it to reflect the new DN (with
        // attribute value changes).
        final RDN originalRDN = dn.getRDN();
        final Entry updatedEntry = originalEntry.duplicate();
        updatedEntry.setDN(newDN);
        if (request.deleteOldRDN()) {
            final String[] oldRDNNames = originalRDN.getAttributeNames();
            final byte[][] oldRDNValues = originalRDN.getByteArrayAttributeValues();
            for (int i = 0; i < oldRDNNames.length; i++) {
                updatedEntry.removeAttributeValue(oldRDNNames[i], oldRDNValues[i]);
            }
        }
        final String[] newRDNNames = newRDN.getAttributeNames();
        final byte[][] newRDNValues = newRDN.getByteArrayAttributeValues();
        for (int i = 0; i < newRDNNames.length; i++) {
            final MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(newRDNNames[i], schema);
            updatedEntry.addAttribute(new Attribute(newRDNNames[i], matchingRule, newRDNValues[i]));
        }
        // If a schema was provided, then make sure the updated entry conforms to
        // the schema.  Also, reject the attempt if any of the new RDN attributes
        // is marked with NO-USER-MODIFICATION.
        final EntryValidator entryValidator = entryValidatorRef.get();
        if (entryValidator != null) {
            final ArrayList<String> invalidReasons = new ArrayList<>(1);
            if (!entryValidator.entryIsValid(updatedEntry, invalidReasons)) {
                return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_VIOLATES_SCHEMA.get(request.getDN(), StaticUtils.concatenateStrings(invalidReasons)), null));
            }
            final String[] oldRDNNames = originalRDN.getAttributeNames();
            for (int i = 0; i < oldRDNNames.length; i++) {
                final String name = oldRDNNames[i];
                final AttributeTypeDefinition at = schema.getAttributeType(name);
                if ((!isInternalOp) && (at != null) && at.isNoUserModification()) {
                    final byte[] value = originalRDN.getByteArrayAttributeValues()[i];
                    if (!updatedEntry.hasAttributeValue(name, value)) {
                        return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.CONSTRAINT_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_NO_USER_MOD.get(request.getDN(), name), null));
                    }
                }
            }
            for (int i = 0; i < newRDNNames.length; i++) {
                final String name = newRDNNames[i];
                final AttributeTypeDefinition at = schema.getAttributeType(name);
                if ((!isInternalOp) && (at != null) && at.isNoUserModification()) {
                    final byte[] value = newRDN.getByteArrayAttributeValues()[i];
                    if (!originalEntry.hasAttributeValue(name, value)) {
                        return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.CONSTRAINT_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_MOD_DN_NO_USER_MOD.get(request.getDN(), name), null));
                    }
                }
            }
        }
        // Perform the appropriate processing for the assertion and proxied
        // authorization controls
        final DN authzDN;
        try {
            handleAssertionRequestControl(controlMap, originalEntry);
            authzDN = handleProxiedAuthControl(controlMap);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        // attributes.
        if (generateOperationalAttributes) {
            updatedEntry.setAttribute(new Attribute("modifiersName", DistinguishedNameMatchingRule.getInstance(), authzDN.toString()));
            updatedEntry.setAttribute(new Attribute("modifyTimestamp", GeneralizedTimeMatchingRule.getInstance(), StaticUtils.encodeGeneralizedTime(new Date())));
            updatedEntry.setAttribute(new Attribute("entryDN", DistinguishedNameMatchingRule.getInstance(), newDN.toNormalizedString()));
        }
        // Perform the appropriate processing for the pre-read and post-read
        // controls.
        final PreReadResponseControl preReadResponse = handlePreReadControl(controlMap, originalEntry);
        if (preReadResponse != null) {
            responseControls.add(preReadResponse);
        }
        final PostReadResponseControl postReadResponse = handlePostReadControl(controlMap, updatedEntry);
        if (postReadResponse != null) {
            responseControls.add(postReadResponse);
        }
        // Remove the old entry and add the new one.
        entryMap.remove(dn);
        entryMap.put(newDN, new ReadOnlyEntry(updatedEntry));
        indexDelete(originalEntry);
        indexAdd(updatedEntry);
        // If the target entry had any subordinates, then rename them as well.
        final RDN[] oldDNComps = dn.getRDNs();
        final RDN[] newDNComps = newDN.getRDNs();
        final Set<DN> dnSet = new LinkedHashSet<>(entryMap.keySet());
        for (final DN mapEntryDN : dnSet) {
            if (mapEntryDN.isDescendantOf(dn, false)) {
                final Entry o = entryMap.remove(mapEntryDN);
                final Entry e = o.duplicate();
                final RDN[] oldMapEntryComps = mapEntryDN.getRDNs();
                final int compsToSave = oldMapEntryComps.length - oldDNComps.length;
                final RDN[] newMapEntryComps = new RDN[compsToSave + newDNComps.length];
                System.arraycopy(oldMapEntryComps, 0, newMapEntryComps, 0, compsToSave);
                System.arraycopy(newDNComps, 0, newMapEntryComps, compsToSave, newDNComps.length);
                final DN newMapEntryDN = new DN(newMapEntryComps);
                e.setDN(newMapEntryDN);
                if (generateOperationalAttributes) {
                    e.setAttribute(new Attribute("entryDN", DistinguishedNameMatchingRule.getInstance(), newMapEntryDN.toNormalizedString()));
                }
                entryMap.put(newMapEntryDN, new ReadOnlyEntry(e));
                indexDelete(o);
                indexAdd(e);
                handleReferentialIntegrityModifyDN(mapEntryDN, newMapEntryDN);
            }
        }
        addChangeLogEntry(request, authzDN);
        handleReferentialIntegrityModifyDN(dn, newDN);
        return new LDAPMessage(messageID, new ModifyDNResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls);
    }
}
Also used : ASN1OctetString(com.unboundid.asn1.ASN1OctetString) LinkedHashSet(java.util.LinkedHashSet) Attribute(com.unboundid.ldap.sdk.Attribute) Schema(com.unboundid.ldap.sdk.schema.Schema) ArrayList(java.util.ArrayList) ModifyDNResponseProtocolOp(com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp) RDN(com.unboundid.ldap.sdk.RDN) DN(com.unboundid.ldap.sdk.DN) ASN1OctetString(com.unboundid.asn1.ASN1OctetString) EntryValidator(com.unboundid.ldap.sdk.schema.EntryValidator) AttributeTypeDefinition(com.unboundid.ldap.sdk.schema.AttributeTypeDefinition) VirtualListViewRequestControl(com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl) SubtreeDeleteRequestControl(com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl) RFC3672SubentriesRequestControl(com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl) SimplePagedResultsControl(com.unboundid.ldap.sdk.controls.SimplePagedResultsControl) VirtualListViewResponseControl(com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl) TransactionSpecificationRequestControl(com.unboundid.ldap.sdk.controls.TransactionSpecificationRequestControl) DraftZeilengaLDAPNoOp12RequestControl(com.unboundid.ldap.sdk.experimental.DraftZeilengaLDAPNoOp12RequestControl) PostReadRequestControl(com.unboundid.ldap.sdk.controls.PostReadRequestControl) ProxiedAuthorizationV1RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl) ServerSideSortResponseControl(com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl) PreReadResponseControl(com.unboundid.ldap.sdk.controls.PreReadResponseControl) AuthorizationIdentityResponseControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl) PermissiveModifyRequestControl(com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl) AuthorizationIdentityRequestControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl) Control(com.unboundid.ldap.sdk.Control) IgnoreNoUserModificationRequestControl(com.unboundid.ldap.sdk.unboundidds.controls.IgnoreNoUserModificationRequestControl) ProxiedAuthorizationV2RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl) ServerSideSortRequestControl(com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) DontUseCopyRequestControl(com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl) AssertionRequestControl(com.unboundid.ldap.sdk.controls.AssertionRequestControl) ManageDsaITRequestControl(com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl) DraftLDUPSubentriesRequestControl(com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl) PreReadRequestControl(com.unboundid.ldap.sdk.controls.PreReadRequestControl) ChangeLogEntry(com.unboundid.ldap.sdk.ChangeLogEntry) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) Entry(com.unboundid.ldap.sdk.Entry) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) RDN(com.unboundid.ldap.sdk.RDN) LDAPMessage(com.unboundid.ldap.protocol.LDAPMessage) Date(java.util.Date) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) LDAPException(com.unboundid.ldap.sdk.LDAPException) PreReadResponseControl(com.unboundid.ldap.sdk.controls.PreReadResponseControl) IntegerMatchingRule(com.unboundid.ldap.matchingrules.IntegerMatchingRule) DistinguishedNameMatchingRule(com.unboundid.ldap.matchingrules.DistinguishedNameMatchingRule) MatchingRule(com.unboundid.ldap.matchingrules.MatchingRule) GeneralizedTimeMatchingRule(com.unboundid.ldap.matchingrules.GeneralizedTimeMatchingRule) NotNull(com.unboundid.util.NotNull)

Example 2 with EntryValidator

use of com.unboundid.ldap.sdk.schema.EntryValidator in project ldapsdk by pingidentity.

the class InMemoryRequestHandler method processAddRequest.

/**
 * Attempts to add an entry to the in-memory data set.  The attempt will fail
 * if any of the following conditions is true:
 * <UL>
 *   <LI>There is a problem with any of the request controls.</LI>
 *   <LI>The provided entry has a malformed DN.</LI>
 *   <LI>The provided entry has the null DN.</LI>
 *   <LI>The provided entry has a DN that is the same as or subordinate to the
 *       subschema subentry.</LI>
 *   <LI>The provided entry has a DN that is the same as or subordinate to the
 *       changelog base entry.</LI>
 *   <LI>An entry already exists with the same DN as the entry in the provided
 *       request.</LI>
 *   <LI>The entry is outside the set of base DNs for the server.</LI>
 *   <LI>The entry is below one of the defined base DNs but the immediate
 *       parent entry does not exist.</LI>
 *   <LI>If a schema was provided, and the entry is not valid according to the
 *       constraints of that schema.</LI>
 * </UL>
 *
 * @param  messageID  The message ID of the LDAP message containing the add
 *                    request.
 * @param  request    The add request that was included in the LDAP message
 *                    that was received.
 * @param  controls   The set of controls included in the LDAP message.  It
 *                    may be empty if there were no controls, but will not be
 *                    {@code null}.
 *
 * @return  The {@link LDAPMessage} containing the response to send to the
 *          client.  The protocol op in the {@code LDAPMessage} must be an
 *          {@code AddResponseProtocolOp}.
 */
@Override()
@NotNull()
public LDAPMessage processAddRequest(final int messageID, @NotNull final AddRequestProtocolOp request, @NotNull final List<Control> controls) {
    synchronized (entryMap) {
        // Sleep before processing, if appropriate.
        sleepBeforeProcessing();
        // Process the provided request controls.
        final Map<String, Control> controlMap;
        try {
            controlMap = RequestControlPreProcessor.processControls(LDAPMessage.PROTOCOL_OP_TYPE_ADD_REQUEST, controls);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        final ArrayList<Control> responseControls = new ArrayList<>(1);
        // If this operation type is not allowed, then reject it.
        final boolean isInternalOp = controlMap.containsKey(OID_INTERNAL_OPERATION_REQUEST_CONTROL);
        if ((!isInternalOp) && (!config.getAllowedOperationTypes().contains(OperationType.ADD))) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_ADD_NOT_ALLOWED.get(), null));
        }
        // client is authenticated.
        if ((authenticatedDN.isNullDN() && config.getAuthenticationRequiredOperationTypes().contains(OperationType.ADD))) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE, null, ERR_MEM_HANDLER_ADD_REQUIRES_AUTH.get(), null));
        }
        // actually doing any further processing.
        try {
            final ASN1OctetString txnID = processTransactionRequest(messageID, request, controlMap);
            if (txnID != null) {
                return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, INFO_MEM_HANDLER_OP_IN_TXN.get(txnID.stringValue()), null));
            }
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(le.getResultCode().intValue(), le.getMatchedDN(), le.getDiagnosticMessage(), StaticUtils.toList(le.getReferralURLs())), le.getResponseControls());
        }
        // Get the entry to be added.  If a schema was provided, then make sure
        // the attributes are created with the appropriate matching rules.
        final Entry entry;
        final Schema schema = schemaRef.get();
        if (schema == null) {
            entry = new Entry(request.getDN(), request.getAttributes());
        } else {
            final List<Attribute> providedAttrs = request.getAttributes();
            final List<Attribute> newAttrs = new ArrayList<>(providedAttrs.size());
            for (final Attribute a : providedAttrs) {
                final String baseName = a.getBaseName();
                final MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(baseName, schema);
                newAttrs.add(new Attribute(a.getName(), matchingRule, a.getRawValues()));
            }
            entry = new Entry(request.getDN(), schema, newAttrs);
        }
        // Make sure that the DN is valid.
        final DN dn;
        try {
            dn = entry.getParsedDN();
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_ADD_MALFORMED_DN.get(request.getDN(), le.getMessage()), null));
        }
        // entry.
        if (dn.isNullDN()) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE, null, ERR_MEM_HANDLER_ADD_ROOT_DSE.get(), null));
        } else if (dn.isDescendantOf(subschemaSubentryDN, true)) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE, null, ERR_MEM_HANDLER_ADD_SCHEMA.get(subschemaSubentryDN.toString()), null));
        } else if (dn.isDescendantOf(changeLogBaseDN, true)) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_ADD_CHANGELOG.get(changeLogBaseDN.toString()), null));
        }
        // See if there is a referral at or above the target entry.
        if (!controlMap.containsKey(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID)) {
            final Entry referralEntry = findNearestReferral(dn);
            if (referralEntry != null) {
                return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.REFERRAL_INT_VALUE, referralEntry.getDN(), INFO_MEM_HANDLER_REFERRAL_ENCOUNTERED.get(), getReferralURLs(dn, referralEntry)));
            }
        }
        // See if another entry exists with the same DN.
        if (entryMap.containsKey(dn)) {
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE, null, ERR_MEM_HANDLER_ADD_ALREADY_EXISTS.get(request.getDN()), null));
        }
        // Make sure that all RDN attribute values are present in the entry.
        final RDN rdn = dn.getRDN();
        final String[] rdnAttrNames = rdn.getAttributeNames();
        final byte[][] rdnAttrValues = rdn.getByteArrayAttributeValues();
        for (int i = 0; i < rdnAttrNames.length; i++) {
            final MatchingRule matchingRule = MatchingRule.selectEqualityMatchingRule(rdnAttrNames[i], schema);
            entry.addAttribute(new Attribute(rdnAttrNames[i], matchingRule, rdnAttrValues[i]));
        }
        // Make sure that all superior object classes are present in the entry.
        if (schema != null) {
            final String[] objectClasses = entry.getObjectClassValues();
            if (objectClasses != null) {
                final LinkedHashMap<String, String> ocMap = new LinkedHashMap<>(StaticUtils.computeMapCapacity(objectClasses.length));
                for (final String ocName : objectClasses) {
                    final ObjectClassDefinition oc = schema.getObjectClass(ocName);
                    if (oc == null) {
                        ocMap.put(StaticUtils.toLowerCase(ocName), ocName);
                    } else {
                        ocMap.put(StaticUtils.toLowerCase(oc.getNameOrOID()), ocName);
                        for (final ObjectClassDefinition supClass : oc.getSuperiorClasses(schema, true)) {
                            ocMap.put(StaticUtils.toLowerCase(supClass.getNameOrOID()), supClass.getNameOrOID());
                        }
                    }
                }
                final String[] newObjectClasses = new String[ocMap.size()];
                ocMap.values().toArray(newObjectClasses);
                entry.setAttribute("objectClass", newObjectClasses);
            }
        }
        // If a schema was provided, then make sure the entry complies with it.
        // Also make sure that there are no attributes marked with
        // NO-USER-MODIFICATION.
        final EntryValidator entryValidator = entryValidatorRef.get();
        if (entryValidator != null) {
            final ArrayList<String> invalidReasons = new ArrayList<>(1);
            if (!entryValidator.entryIsValid(entry, invalidReasons)) {
                return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_ADD_VIOLATES_SCHEMA.get(request.getDN(), StaticUtils.concatenateStrings(invalidReasons)), null));
            }
            if ((!isInternalOp) && (schema != null) && (!controlMap.containsKey(IgnoreNoUserModificationRequestControl.IGNORE_NO_USER_MODIFICATION_REQUEST_OID))) {
                for (final Attribute a : entry.getAttributes()) {
                    final AttributeTypeDefinition at = schema.getAttributeType(a.getBaseName());
                    if ((at != null) && at.isNoUserModification()) {
                        return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.CONSTRAINT_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_ADD_CONTAINS_NO_USER_MOD.get(request.getDN(), a.getName()), null));
                    }
                }
            }
        }
        // If the entry contains a proxied authorization control, then process it.
        final DN authzDN;
        try {
            authzDN = handleProxiedAuthControl(controlMap);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        // Add a number of operational attributes to the entry.
        if (generateOperationalAttributes) {
            final Date d = new Date();
            if (!entry.hasAttribute("entryDN")) {
                entry.addAttribute(new Attribute("entryDN", DistinguishedNameMatchingRule.getInstance(), dn.toNormalizedString()));
            }
            if (!entry.hasAttribute("entryUUID")) {
                entry.addAttribute(new Attribute("entryUUID", CryptoHelper.getRandomUUID().toString()));
            }
            if (!entry.hasAttribute("subschemaSubentry")) {
                entry.addAttribute(new Attribute("subschemaSubentry", DistinguishedNameMatchingRule.getInstance(), subschemaSubentryDN.toString()));
            }
            if (!entry.hasAttribute("creatorsName")) {
                entry.addAttribute(new Attribute("creatorsName", DistinguishedNameMatchingRule.getInstance(), authzDN.toString()));
            }
            if (!entry.hasAttribute("createTimestamp")) {
                entry.addAttribute(new Attribute("createTimestamp", GeneralizedTimeMatchingRule.getInstance(), StaticUtils.encodeGeneralizedTime(d)));
            }
            if (!entry.hasAttribute("modifiersName")) {
                entry.addAttribute(new Attribute("modifiersName", DistinguishedNameMatchingRule.getInstance(), authzDN.toString()));
            }
            if (!entry.hasAttribute("modifyTimestamp")) {
                entry.addAttribute(new Attribute("modifyTimestamp", GeneralizedTimeMatchingRule.getInstance(), StaticUtils.encodeGeneralizedTime(d)));
            }
        }
        // now.
        try {
            handleAssertionRequestControl(controlMap, entry);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        // values are properly encoded.
        if ((!passwordEncoders.isEmpty()) && (!configuredPasswordAttributes.isEmpty())) {
            final ReadOnlyEntry readOnlyEntry = new ReadOnlyEntry(entry.duplicate());
            for (final String passwordAttribute : configuredPasswordAttributes) {
                for (final Attribute attr : readOnlyEntry.getAttributesWithOptions(passwordAttribute, null)) {
                    final ArrayList<byte[]> newValues = new ArrayList<>(attr.size());
                    for (final ASN1OctetString value : attr.getRawValues()) {
                        try {
                            newValues.add(encodeAddPassword(value, readOnlyEntry, Collections.<Modification>emptyList()).getValue());
                        } catch (final LDAPException le) {
                            Debug.debugException(le);
                            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, le.getMatchedDN(), le.getMessage(), null));
                        }
                    }
                    final byte[][] newValuesArray = new byte[newValues.size()][];
                    newValues.toArray(newValuesArray);
                    entry.setAttribute(new Attribute(attr.getName(), schema, newValuesArray));
                }
            }
        }
        // If the request includes the post-read request control, then create the
        // appropriate response control.
        final PostReadResponseControl postReadResponse = handlePostReadControl(controlMap, entry);
        if (postReadResponse != null) {
            responseControls.add(postReadResponse);
        }
        // add the entry.
        if (baseDNs.contains(dn)) {
            entryMap.put(dn, new ReadOnlyEntry(entry));
            indexAdd(entry);
            addChangeLogEntry(request, authzDN);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls);
        }
        // See if the parent entry exists.  If so, then we can add the entry.
        final DN parentDN = dn.getParent();
        if ((parentDN != null) && entryMap.containsKey(parentDN)) {
            entryMap.put(dn, new ReadOnlyEntry(entry));
            indexAdd(entry);
            addChangeLogEntry(request, authzDN);
            return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls);
        }
        // within any of the configured base DNs.
        for (final DN baseDN : baseDNs) {
            if (dn.isDescendantOf(baseDN, true)) {
                return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), ERR_MEM_HANDLER_ADD_MISSING_PARENT.get(request.getDN(), dn.getParentString()), null));
            }
        }
        return new LDAPMessage(messageID, new AddResponseProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, null, ERR_MEM_HANDLER_ADD_NOT_BELOW_BASE_DN.get(request.getDN()), null));
    }
}
Also used : ASN1OctetString(com.unboundid.asn1.ASN1OctetString) Attribute(com.unboundid.ldap.sdk.Attribute) Schema(com.unboundid.ldap.sdk.schema.Schema) ArrayList(java.util.ArrayList) AddResponseProtocolOp(com.unboundid.ldap.protocol.AddResponseProtocolOp) RDN(com.unboundid.ldap.sdk.RDN) DN(com.unboundid.ldap.sdk.DN) ASN1OctetString(com.unboundid.asn1.ASN1OctetString) EntryValidator(com.unboundid.ldap.sdk.schema.EntryValidator) LinkedHashMap(java.util.LinkedHashMap) AttributeTypeDefinition(com.unboundid.ldap.sdk.schema.AttributeTypeDefinition) VirtualListViewRequestControl(com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl) SubtreeDeleteRequestControl(com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl) RFC3672SubentriesRequestControl(com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl) SimplePagedResultsControl(com.unboundid.ldap.sdk.controls.SimplePagedResultsControl) VirtualListViewResponseControl(com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl) TransactionSpecificationRequestControl(com.unboundid.ldap.sdk.controls.TransactionSpecificationRequestControl) DraftZeilengaLDAPNoOp12RequestControl(com.unboundid.ldap.sdk.experimental.DraftZeilengaLDAPNoOp12RequestControl) PostReadRequestControl(com.unboundid.ldap.sdk.controls.PostReadRequestControl) ProxiedAuthorizationV1RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl) ServerSideSortResponseControl(com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl) PreReadResponseControl(com.unboundid.ldap.sdk.controls.PreReadResponseControl) AuthorizationIdentityResponseControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl) PermissiveModifyRequestControl(com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl) AuthorizationIdentityRequestControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl) Control(com.unboundid.ldap.sdk.Control) IgnoreNoUserModificationRequestControl(com.unboundid.ldap.sdk.unboundidds.controls.IgnoreNoUserModificationRequestControl) ProxiedAuthorizationV2RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl) ServerSideSortRequestControl(com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) DontUseCopyRequestControl(com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl) AssertionRequestControl(com.unboundid.ldap.sdk.controls.AssertionRequestControl) ManageDsaITRequestControl(com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl) DraftLDUPSubentriesRequestControl(com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl) PreReadRequestControl(com.unboundid.ldap.sdk.controls.PreReadRequestControl) ChangeLogEntry(com.unboundid.ldap.sdk.ChangeLogEntry) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) Entry(com.unboundid.ldap.sdk.Entry) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) RDN(com.unboundid.ldap.sdk.RDN) ObjectClassDefinition(com.unboundid.ldap.sdk.schema.ObjectClassDefinition) LDAPMessage(com.unboundid.ldap.protocol.LDAPMessage) Date(java.util.Date) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) LDAPException(com.unboundid.ldap.sdk.LDAPException) IntegerMatchingRule(com.unboundid.ldap.matchingrules.IntegerMatchingRule) DistinguishedNameMatchingRule(com.unboundid.ldap.matchingrules.DistinguishedNameMatchingRule) MatchingRule(com.unboundid.ldap.matchingrules.MatchingRule) GeneralizedTimeMatchingRule(com.unboundid.ldap.matchingrules.GeneralizedTimeMatchingRule) NotNull(com.unboundid.util.NotNull)

Example 3 with EntryValidator

use of com.unboundid.ldap.sdk.schema.EntryValidator in project ldapsdk by pingidentity.

the class ValidateLDIFTestCase method testCountMultipleStructuralObjects.

/**
 * Performs a test to validate count of multiple structural
 * objects on an entry.
 *
 * @throws Exception If an unexpected problem occurs.
 */
@Test()
public void testCountMultipleStructuralObjects() throws Exception {
    if (!isDirectoryInstanceAvailable()) {
        return;
    }
    File rejectFile = File.createTempFile("reject", ".ldif");
    File structuralLdif = createTempFile("dn:dc = example, dc = com", "objectClass: top", "objectClass: domain", "dc: example", "", "dn: ou = People, dc = example, dc = com", "objectClass: top", "objectClass: organizationalUnit", "objectClass: domain", "ou: People", "dc: subdomain", "", "dn: uid = user.0, ou = People, dc = example, dc = com", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "objectClass: crlDistributionPoint", "uid: user.0", "cn: Aaren Atp", "sn: Atp");
    String[] args = { "--schemaDirectory", schemaDir.getAbsolutePath().toString(), "-f", structuralLdif.getAbsolutePath().toString(), "-R", rejectFile.getAbsolutePath().toString() };
    ValidateLDIF validateLDIF = new ValidateLDIF(null, null);
    validateLDIF.runTool(args);
    EntryValidator entryValidator = validateLDIF.getEntryValidator();
    assertEquals(entryValidator.getEntriesWithMultipleStructuralObjectClasses(), 2);
}
Also used : File(java.io.File) EntryValidator(com.unboundid.ldap.sdk.schema.EntryValidator) Test(org.testng.annotations.Test)

Example 4 with EntryValidator

use of com.unboundid.ldap.sdk.schema.EntryValidator in project ldapsdk by pingidentity.

the class LDIFSearch method doToolProcessing.

/**
 * {@inheritDoc}
 */
@Override()
@NotNull()
public ResultCode doToolProcessing() {
    // Get the schema to use when performing LDIF processing.
    final Schema schema;
    try {
        if (schemaPath.isPresent()) {
            schema = getSchema(schemaPath.getValues());
        } else if (PING_SERVER_AVAILABLE) {
            schema = getSchema(Collections.singletonList(StaticUtils.constructPath(PING_SERVER_ROOT, "config", "schema")));
        } else {
            schema = Schema.getDefaultStandardSchema();
        }
    } catch (final Exception e) {
        Debug.debugException(e);
        logCompletionMessage(true, ERR_LDIFSEARCH_CANNOT_GET_SCHEMA.get(StaticUtils.getExceptionMessage(e)));
        return ResultCode.LOCAL_ERROR;
    }
    // Create search entry parers for all of the search URLs.
    final Map<LDAPURL, SearchEntryParer> urlMap = new LinkedHashMap<>();
    for (final LDAPURL url : searchURLs) {
        final SearchEntryParer parer = new SearchEntryParer(Arrays.asList(url.getAttributes()), schema);
        urlMap.put(url, parer);
    }
    // If we should check schema, then create the entry validator.
    final EntryValidator entryValidator;
    if (checkSchema.isPresent()) {
        entryValidator = new EntryValidator(schema);
    } else {
        entryValidator = null;
    }
    // Create the output files, if appropriate.
    OutputStream outputStream = null;
    SearchEntryParer singleParer = null;
    final Map<LDAPURL, LDIFSearchSeparateSearchDetails> separateWriters = new LinkedHashMap<>();
    try {
        if (outputFile.isPresent()) {
            final int numURLs = searchURLs.size();
            if (separateOutputFilePerSearch.isPresent() && (numURLs > 1)) {
                int i = 1;
                for (final LDAPURL url : searchURLs) {
                    final File f = new File(outputFile.getValue().getAbsolutePath() + '.' + i);
                    final LDIFSearchSeparateSearchDetails details = new LDIFSearchSeparateSearchDetails(url, f, createLDIFWriter(f, url), schema);
                    separateWriters.put(url, details);
                    i++;
                }
            } else {
                try {
                    outputStream = createOutputStream(outputFile.getValue());
                    resultWriter.updateOutputStream(outputStream);
                } catch (final Exception e) {
                    Debug.debugException(e);
                    throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_LDIFSEARCH_CANNOT_WRITE_TO_FILE.get(outputFile.getValue().getAbsolutePath(), StaticUtils.getExceptionMessage(e)), e);
                }
            }
        }
        // to the top of the output.
        if (separateWriters.isEmpty()) {
            resultWriter.writeHeader();
        }
        // Iterate through the LDIF files and process the entries they contain.
        boolean errorEncountered = false;
        final List<LDAPURL> matchingURLs = new ArrayList<>();
        final List<String> entryInvalidReasons = new ArrayList<>();
        for (final File f : ldifFile.getValues()) {
            final LDIFReader ldifReader;
            try {
                ldifReader = new LDIFReader(openInputStream(f));
                if (stripTrailingSpaces.isPresent()) {
                    ldifReader.setTrailingSpaceBehavior(TrailingSpaceBehavior.STRIP);
                } else {
                    ldifReader.setTrailingSpaceBehavior(TrailingSpaceBehavior.REJECT);
                }
            } catch (final Exception e) {
                Debug.debugException(e);
                logCompletionMessage(true, ERR_LDIFSEARCH_CANNOT_OPEN_LDIF_FILE.get(f.getName(), StaticUtils.getExceptionMessage(e)));
                return ResultCode.LOCAL_ERROR;
            }
            try {
                while (true) {
                    final Entry entry;
                    try {
                        entry = ldifReader.readEntry();
                    } catch (final LDIFException e) {
                        Debug.debugException(e);
                        if (e.mayContinueReading()) {
                            commentToErr(ERR_LDIFSEARCH_RECOVERABLE_READ_ERROR.get(f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)));
                            errorEncountered = true;
                            continue;
                        } else {
                            logCompletionMessage(true, ERR_LDIFSEARCH_UNRECOVERABLE_READ_ERROR.get(f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)));
                            return ResultCode.LOCAL_ERROR;
                        }
                    } catch (final Exception e) {
                        logCompletionMessage(true, ERR_LDIFSEARCH_UNRECOVERABLE_READ_ERROR.get(f.getAbsolutePath(), StaticUtils.getExceptionMessage(e)));
                        return ResultCode.LOCAL_ERROR;
                    }
                    if (entry == null) {
                        break;
                    }
                    if (entryValidator != null) {
                        entryInvalidReasons.clear();
                        if (!entryValidator.entryIsValid(entry, entryInvalidReasons)) {
                            commentToErr(ERR_LDIFSEARCH_ENTRY_VIOLATES_SCHEMA.get(entry.getDN()));
                            for (final String invalidReason : entryInvalidReasons) {
                                commentToErr("- " + invalidReason);
                            }
                            err();
                            errorEncountered = true;
                            continue;
                        }
                    }
                    if (separateWriters.isEmpty()) {
                        matchingURLs.clear();
                        for (final LDAPURL url : searchURLs) {
                            if (urlMatchesEntry(url, entry)) {
                                matchingURLs.add(url);
                            }
                        }
                        if (matchingURLs.isEmpty()) {
                            continue;
                        }
                        try {
                            if (searchURLs.size() > 1) {
                                resultWriter.writeComment(INFO_LDIFSEARCH_ENTRY_MATCHES_URLS.get(entry.getDN()));
                                for (final LDAPURL url : matchingURLs) {
                                    resultWriter.writeComment(url.toString());
                                }
                            }
                            if (singleParer == null) {
                                singleParer = new SearchEntryParer(Arrays.asList(searchURLs.get(0).getAttributes()), schema);
                            }
                            resultWriter.writeSearchResultEntry(new SearchResultEntry(singleParer.pareEntry(entry)));
                            if (!outputFile.isPresent()) {
                                resultWriter.flush();
                            }
                        } catch (final Exception e) {
                            Debug.debugException(e);
                            if (outputFile.isPresent()) {
                                logCompletionMessage(true, ERR_LDIFSEARCH_WRITE_ERROR_WITH_FILE.get(entry.getDN(), outputFile.getValue().getAbsolutePath(), StaticUtils.getExceptionMessage(e)));
                            } else {
                                logCompletionMessage(true, ERR_LDIFSEARCH_WRITE_ERROR_NO_FILE.get(entry.getDN(), StaticUtils.getExceptionMessage(e)));
                            }
                            return ResultCode.LOCAL_ERROR;
                        }
                    } else {
                        for (final LDIFSearchSeparateSearchDetails details : separateWriters.values()) {
                            final LDAPURL url = details.getLDAPURL();
                            if (urlMatchesEntry(url, entry)) {
                                try {
                                    final Entry paredEntry = details.getSearchEntryParer().pareEntry(entry);
                                    details.getLDIFWriter().writeEntry(paredEntry);
                                } catch (final Exception ex) {
                                    Debug.debugException(ex);
                                    logCompletionMessage(true, ERR_LDIFSEARCH_WRITE_ERROR_WITH_FILE.get(entry.getDN(), details.getOutputFile().getAbsolutePath(), StaticUtils.getExceptionMessage(ex)));
                                    return ResultCode.LOCAL_ERROR;
                                }
                            }
                        }
                    }
                }
            } finally {
                try {
                    ldifReader.close();
                } catch (final Exception e) {
                    Debug.debugException(e);
                }
            }
        }
        if (errorEncountered) {
            logCompletionMessage(true, WARN_LDIFSEARCH_COMPLETED_WITH_ERRORS.get());
            return ResultCode.PARAM_ERROR;
        } else {
            logCompletionMessage(false, INFO_LDIFSEARCH_COMPLETED_SUCCESSFULLY.get());
            return ResultCode.SUCCESS;
        }
    } catch (final LDAPException e) {
        Debug.debugException(e);
        logCompletionMessage(true, e.getMessage());
        return e.getResultCode();
    } finally {
        try {
            resultWriter.flush();
            if (outputStream != null) {
                outputStream.close();
            }
        } catch (final Exception e) {
            Debug.debugException(e);
        }
        for (final LDIFSearchSeparateSearchDetails details : separateWriters.values()) {
            try {
                details.getLDIFWriter().close();
            } catch (final Exception e) {
                Debug.debugException(e);
            }
        }
    }
}
Also used : Schema(com.unboundid.ldap.sdk.schema.Schema) PassphraseEncryptedOutputStream(com.unboundid.util.PassphraseEncryptedOutputStream) GZIPOutputStream(java.util.zip.GZIPOutputStream) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) ArrayList(java.util.ArrayList) EntryValidator(com.unboundid.ldap.sdk.schema.EntryValidator) ArgumentException(com.unboundid.util.args.ArgumentException) LDAPException(com.unboundid.ldap.sdk.LDAPException) IOException(java.io.IOException) SearchEntryParer(com.unboundid.ldap.listener.SearchEntryParer) LinkedHashMap(java.util.LinkedHashMap) Entry(com.unboundid.ldap.sdk.Entry) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) LDAPURL(com.unboundid.ldap.sdk.LDAPURL) LDAPException(com.unboundid.ldap.sdk.LDAPException) File(java.io.File) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) NotNull(com.unboundid.util.NotNull)

Example 5 with EntryValidator

use of com.unboundid.ldap.sdk.schema.EntryValidator in project ldapsdk by pingidentity.

the class InMemoryRequestHandler method processModifyRequest.

/**
 * Attempts to process the provided modify request.  The attempt will fail if
 * any of the following conditions is true:
 * <UL>
 *   <LI>There is a problem with any of the request controls.</LI>
 *   <LI>The modify request contains a malformed target DN.</LI>
 *   <LI>The target entry is the root DSE.</LI>
 *   <LI>The target entry is the subschema subentry.</LI>
 *   <LI>The target entry does not exist.</LI>
 *   <LI>Any of the modifications cannot be applied to the entry.</LI>
 *   <LI>If a schema was provided, and the entry violates any of the
 *       constraints of that schema.</LI>
 * </UL>
 *
 * @param  messageID  The message ID of the LDAP message containing the modify
 *                    request.
 * @param  request    The modify request that was included in the LDAP message
 *                    that was received.
 * @param  controls   The set of controls included in the LDAP message.  It
 *                    may be empty if there were no controls, but will not be
 *                    {@code null}.
 *
 * @return  The {@link LDAPMessage} containing the response to send to the
 *          client.  The protocol op in the {@code LDAPMessage} must be an
 *          {@code ModifyResponseProtocolOp}.
 */
@Override()
@NotNull()
public LDAPMessage processModifyRequest(final int messageID, @NotNull final ModifyRequestProtocolOp request, @NotNull final List<Control> controls) {
    synchronized (entryMap) {
        // Sleep before processing, if appropriate.
        sleepBeforeProcessing();
        // Process the provided request controls.
        final Map<String, Control> controlMap;
        try {
            controlMap = RequestControlPreProcessor.processControls(LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_REQUEST, controls);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        final ArrayList<Control> responseControls = new ArrayList<>(1);
        // If this operation type is not allowed, then reject it.
        final boolean isInternalOp = controlMap.containsKey(OID_INTERNAL_OPERATION_REQUEST_CONTROL);
        if ((!isInternalOp) && (!config.getAllowedOperationTypes().contains(OperationType.MODIFY))) {
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MODIFY_NOT_ALLOWED.get(), null));
        }
        // client is authenticated.
        if ((authenticatedDN.isNullDN() && config.getAuthenticationRequiredOperationTypes().contains(OperationType.MODIFY))) {
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE, null, ERR_MEM_HANDLER_MODIFY_REQUIRES_AUTH.get(), null));
        }
        // without actually doing any further processing.
        try {
            final ASN1OctetString txnID = processTransactionRequest(messageID, request, controlMap);
            if (txnID != null) {
                return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, INFO_MEM_HANDLER_OP_IN_TXN.get(txnID.stringValue()), null));
            }
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), le.getMatchedDN(), le.getDiagnosticMessage(), StaticUtils.toList(le.getReferralURLs())), le.getResponseControls());
        }
        // Get the parsed target DN.
        final DN dn;
        final Schema schema = schemaRef.get();
        try {
            dn = new DN(request.getDN(), schema);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_MOD_MALFORMED_DN.get(request.getDN(), le.getMessage()), null));
        }
        // See if the target entry or one of its superiors is a smart referral.
        if (!controlMap.containsKey(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID)) {
            final Entry referralEntry = findNearestReferral(dn);
            if (referralEntry != null) {
                return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.REFERRAL_INT_VALUE, referralEntry.getDN(), INFO_MEM_HANDLER_REFERRAL_ENCOUNTERED.get(), getReferralURLs(dn, referralEntry)));
            }
        }
        // changelog entry.
        if (dn.isNullDN()) {
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_ROOT_DSE.get(), null));
        } else if (dn.equals(subschemaSubentryDN)) {
            try {
                validateSchemaMods(request);
            } catch (final LDAPException le) {
                return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), le.getMatchedDN(), le.getMessage(), null));
            }
        } else if (dn.isDescendantOf(changeLogBaseDN, true)) {
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_MOD_CHANGELOG.get(request.getDN()), null));
        }
        // Get the target entry.  If it does not exist, then fail.
        Entry entry = entryMap.get(dn);
        if (entry == null) {
            if (dn.equals(subschemaSubentryDN)) {
                entry = subschemaSubentryRef.get().duplicate();
            } else {
                return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.NO_SUCH_OBJECT_INT_VALUE, getMatchedDNString(dn), ERR_MEM_HANDLER_MOD_NO_SUCH_ENTRY.get(request.getDN()), null));
            }
        }
        // If any of the modifications target password attributes, then make sure
        // they are properly encoded.
        final ReadOnlyEntry readOnlyEntry = new ReadOnlyEntry(entry);
        final List<Modification> unencodedMods = request.getModifications();
        final ArrayList<Modification> modifications = new ArrayList<>(unencodedMods.size());
        for (final Modification m : unencodedMods) {
            try {
                modifications.add(encodeModificationPasswords(m, readOnlyEntry, unencodedMods));
            } catch (final LDAPException le) {
                Debug.debugException(le);
                if (le.getResultCode().isClientSideResultCode()) {
                    return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, le.getMatchedDN(), le.getMessage(), null));
                } else {
                    return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), le.getMatchedDN(), le.getMessage(), null));
                }
            }
        }
        // Attempt to apply the modifications to the entry.  If successful, then a
        // copy of the entry will be returned with the modifications applied.
        final Entry modifiedEntry;
        try {
            modifiedEntry = Entry.applyModifications(entry, controlMap.containsKey(PermissiveModifyRequestControl.PERMISSIVE_MODIFY_REQUEST_OID), modifications);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), null, ERR_MEM_HANDLER_MOD_FAILED.get(request.getDN(), le.getMessage()), null));
        }
        // If a schema was provided, use it to validate the resulting entry.
        // Also, ensure that no NO-USER-MODIFICATION attributes were targeted.
        final EntryValidator entryValidator = entryValidatorRef.get();
        if (entryValidator != null) {
            final ArrayList<String> invalidReasons = new ArrayList<>(1);
            if (!entryValidator.entryIsValid(modifiedEntry, invalidReasons)) {
                return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_MOD_VIOLATES_SCHEMA.get(request.getDN(), StaticUtils.concatenateStrings(invalidReasons)), null));
            }
            for (final Modification m : modifications) {
                final Attribute a = m.getAttribute();
                final String baseName = a.getBaseName();
                final AttributeTypeDefinition at = schema.getAttributeType(baseName);
                if ((!isInternalOp) && (at != null) && at.isNoUserModification()) {
                    return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.CONSTRAINT_VIOLATION_INT_VALUE, null, ERR_MEM_HANDLER_MOD_NO_USER_MOD.get(request.getDN(), a.getName()), null));
                }
            }
        }
        // Perform the appropriate processing for the assertion and proxied
        // authorization controls.
        // Perform the appropriate processing for the assertion, pre-read,
        // post-read, and proxied authorization controls.
        final DN authzDN;
        try {
            handleAssertionRequestControl(controlMap, entry);
            authzDN = handleProxiedAuthControl(controlMap);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new ModifyResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null));
        }
        // Update modifiersName and modifyTimestamp.
        if (generateOperationalAttributes) {
            modifiedEntry.setAttribute(new Attribute("modifiersName", DistinguishedNameMatchingRule.getInstance(), authzDN.toString()));
            modifiedEntry.setAttribute(new Attribute("modifyTimestamp", GeneralizedTimeMatchingRule.getInstance(), StaticUtils.encodeGeneralizedTime(new Date())));
        }
        // Perform the appropriate processing for the pre-read and post-read
        // controls.
        final PreReadResponseControl preReadResponse = handlePreReadControl(controlMap, entry);
        if (preReadResponse != null) {
            responseControls.add(preReadResponse);
        }
        final PostReadResponseControl postReadResponse = handlePostReadControl(controlMap, modifiedEntry);
        if (postReadResponse != null) {
            responseControls.add(postReadResponse);
        }
        // Replace the entry in the map and return a success result.
        if (dn.equals(subschemaSubentryDN)) {
            final Schema newSchema = new Schema(modifiedEntry);
            subschemaSubentryRef.set(new ReadOnlyEntry(modifiedEntry));
            schemaRef.set(newSchema);
            entryValidatorRef.set(new EntryValidator(newSchema));
        } else {
            entryMap.put(dn, new ReadOnlyEntry(modifiedEntry));
            indexDelete(entry);
            indexAdd(modifiedEntry);
        }
        addChangeLogEntry(request, authzDN);
        return new LDAPMessage(messageID, new ModifyResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null), responseControls);
    }
}
Also used : ASN1OctetString(com.unboundid.asn1.ASN1OctetString) Modification(com.unboundid.ldap.sdk.Modification) Attribute(com.unboundid.ldap.sdk.Attribute) Schema(com.unboundid.ldap.sdk.schema.Schema) LDAPMessage(com.unboundid.ldap.protocol.LDAPMessage) ArrayList(java.util.ArrayList) RDN(com.unboundid.ldap.sdk.RDN) DN(com.unboundid.ldap.sdk.DN) ASN1OctetString(com.unboundid.asn1.ASN1OctetString) EntryValidator(com.unboundid.ldap.sdk.schema.EntryValidator) Date(java.util.Date) AttributeTypeDefinition(com.unboundid.ldap.sdk.schema.AttributeTypeDefinition) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) VirtualListViewRequestControl(com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl) SubtreeDeleteRequestControl(com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl) RFC3672SubentriesRequestControl(com.unboundid.ldap.sdk.controls.RFC3672SubentriesRequestControl) SimplePagedResultsControl(com.unboundid.ldap.sdk.controls.SimplePagedResultsControl) VirtualListViewResponseControl(com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl) TransactionSpecificationRequestControl(com.unboundid.ldap.sdk.controls.TransactionSpecificationRequestControl) DraftZeilengaLDAPNoOp12RequestControl(com.unboundid.ldap.sdk.experimental.DraftZeilengaLDAPNoOp12RequestControl) PostReadRequestControl(com.unboundid.ldap.sdk.controls.PostReadRequestControl) ProxiedAuthorizationV1RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl) ServerSideSortResponseControl(com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl) PreReadResponseControl(com.unboundid.ldap.sdk.controls.PreReadResponseControl) AuthorizationIdentityResponseControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl) PermissiveModifyRequestControl(com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl) AuthorizationIdentityRequestControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl) Control(com.unboundid.ldap.sdk.Control) IgnoreNoUserModificationRequestControl(com.unboundid.ldap.sdk.unboundidds.controls.IgnoreNoUserModificationRequestControl) ProxiedAuthorizationV2RequestControl(com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl) ServerSideSortRequestControl(com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) DontUseCopyRequestControl(com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl) AssertionRequestControl(com.unboundid.ldap.sdk.controls.AssertionRequestControl) ManageDsaITRequestControl(com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl) DraftLDUPSubentriesRequestControl(com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl) PreReadRequestControl(com.unboundid.ldap.sdk.controls.PreReadRequestControl) ChangeLogEntry(com.unboundid.ldap.sdk.ChangeLogEntry) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) Entry(com.unboundid.ldap.sdk.Entry) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) LDAPException(com.unboundid.ldap.sdk.LDAPException) PreReadResponseControl(com.unboundid.ldap.sdk.controls.PreReadResponseControl) ModifyResponseProtocolOp(com.unboundid.ldap.protocol.ModifyResponseProtocolOp) PostReadResponseControl(com.unboundid.ldap.sdk.controls.PostReadResponseControl) NotNull(com.unboundid.util.NotNull)

Aggregations

EntryValidator (com.unboundid.ldap.sdk.schema.EntryValidator)6 Entry (com.unboundid.ldap.sdk.Entry)5 LDAPException (com.unboundid.ldap.sdk.LDAPException)5 Schema (com.unboundid.ldap.sdk.schema.Schema)5 SearchResultEntry (com.unboundid.ldap.sdk.SearchResultEntry)4 ASN1OctetString (com.unboundid.asn1.ASN1OctetString)3 LDAPMessage (com.unboundid.ldap.protocol.LDAPMessage)3 Attribute (com.unboundid.ldap.sdk.Attribute)3 ChangeLogEntry (com.unboundid.ldap.sdk.ChangeLogEntry)3 Control (com.unboundid.ldap.sdk.Control)3 DN (com.unboundid.ldap.sdk.DN)3 RDN (com.unboundid.ldap.sdk.RDN)3 ReadOnlyEntry (com.unboundid.ldap.sdk.ReadOnlyEntry)3 AssertionRequestControl (com.unboundid.ldap.sdk.controls.AssertionRequestControl)3 AuthorizationIdentityRequestControl (com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl)3 AuthorizationIdentityResponseControl (com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl)3 DontUseCopyRequestControl (com.unboundid.ldap.sdk.controls.DontUseCopyRequestControl)3 DraftLDUPSubentriesRequestControl (com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl)3 ManageDsaITRequestControl (com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl)3 PermissiveModifyRequestControl (com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl)3