Search in sources :

Example 6 with ReadOnlyEntry

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

the class InMemoryRequestHandler method processBindRequest.

/**
 * Attempts to process the provided bind 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 bind request is for a SASL bind for which no SASL mechanism
 *       handler is defined.</LI>
 *   <LI>The bind request contains a malformed bind DN.</LI>
 *   <LI>The bind DN is not the null DN and is not the DN of any entry in the
 *       data set.</LI>
 *   <LI>The bind password is empty and the bind DN is not the null DN.</LI>
 *   <LI>The target user does not have any password value that matches the
 *       provided bind password.</LI>
 * </UL>
 *
 * @param  messageID  The message ID of the LDAP message containing the bind
 *                    request.
 * @param  request    The bind 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 a
 *          {@code BindResponseProtocolOp}.
 */
@Override()
@NotNull()
public LDAPMessage processBindRequest(final int messageID, @NotNull final BindRequestProtocolOp request, @NotNull final List<Control> controls) {
    synchronized (entryMap) {
        // Sleep before processing, if appropriate.
        sleepBeforeProcessing();
        // If this operation type is not allowed, then reject it.
        if (!config.getAllowedOperationTypes().contains(OperationType.BIND)) {
            return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_BIND_NOT_ALLOWED.get(), null, null));
        }
        authenticatedDN = DN.NULL_DN;
        // request, then ensure that the request includes credentials.
        if ((authenticatedDN.isNullDN() && config.getAuthenticationRequiredOperationTypes().contains(OperationType.BIND))) {
            if ((request.getCredentialsType() == BindRequestProtocolOp.CRED_TYPE_SIMPLE) && ((request.getSimplePassword() == null) || request.getSimplePassword().getValueLength() == 0)) {
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_REQUIRES_AUTH.get(), null, null));
            }
        }
        // Get the parsed bind DN.
        final DN bindDN;
        try {
            bindDN = new DN(request.getBindDN(), schemaRef.get());
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_DN_SYNTAX_INT_VALUE, null, ERR_MEM_HANDLER_BIND_MALFORMED_DN.get(request.getBindDN(), le.getMessage()), null, null));
        }
        // mechanism handler that can be used to process it.
        if (request.getCredentialsType() == BindRequestProtocolOp.CRED_TYPE_SASL) {
            final String mechanism = request.getSASLMechanism();
            final InMemorySASLBindHandler handler = saslBindHandlers.get(mechanism);
            if (handler == null) {
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.AUTH_METHOD_NOT_SUPPORTED_INT_VALUE, null, ERR_MEM_HANDLER_SASL_MECH_NOT_SUPPORTED.get(mechanism), null, null));
            }
            try {
                final BindResult bindResult = handler.processSASLBind(this, messageID, bindDN, request.getSASLCredentials(), controls);
                // unauthenticated, then see if we allow that.
                if ((bindResult.getResultCode() == ResultCode.SUCCESS) && (authenticatedDN == DN.NULL_DN) && config.getAuthenticationRequiredOperationTypes().contains(OperationType.BIND)) {
                    return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_REQUIRES_AUTH.get(), null, null));
                }
                return new LDAPMessage(messageID, new BindResponseProtocolOp(bindResult.getResultCode().intValue(), bindResult.getMatchedDN(), bindResult.getDiagnosticMessage(), Arrays.asList(bindResult.getReferralURLs()), bindResult.getServerSASLCredentials()), Arrays.asList(bindResult.getResponseControls()));
            } catch (final Exception e) {
                Debug.debugException(e);
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.OTHER_INT_VALUE, null, ERR_MEM_HANDLER_SASL_BIND_FAILURE.get(StaticUtils.getExceptionMessage(e)), null, null));
            }
        }
        // If we've gotten here, then the bind must use simple authentication.
        // Process the provided request controls.
        final Map<String, Control> controlMap;
        try {
            controlMap = RequestControlPreProcessor.processControls(LDAPMessage.PROTOCOL_OP_TYPE_BIND_REQUEST, controls);
        } catch (final LDAPException le) {
            Debug.debugException(le);
            return new LDAPMessage(messageID, new BindResponseProtocolOp(le.getResultCode().intValue(), null, le.getMessage(), null, null));
        }
        final ArrayList<Control> responseControls = new ArrayList<>(1);
        // If the bind DN is the null DN, then the bind will be considered
        // successful as long as the password is also empty.
        final ASN1OctetString bindPassword = request.getSimplePassword();
        if (bindDN.isNullDN()) {
            if (bindPassword.getValueLength() == 0) {
                if (controlMap.containsKey(AuthorizationIdentityRequestControl.AUTHORIZATION_IDENTITY_REQUEST_OID)) {
                    responseControls.add(new AuthorizationIdentityResponseControl(""));
                }
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null, null), responseControls);
            } else {
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_WRONG_PASSWORD.get(request.getBindDN()), null, null));
            }
        }
        // request.
        if ((!bindDN.isNullDN()) && (bindPassword.getValueLength() == 0)) {
            return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.UNWILLING_TO_PERFORM_INT_VALUE, null, ERR_MEM_HANDLER_BIND_SIMPLE_DN_WITHOUT_PASSWORD.get(), null, null));
        }
        // See if the bind DN is in the set of additional bind credentials.  If
        // so, then use the password there.
        final byte[] additionalCreds = additionalBindCredentials.get(bindDN);
        if (additionalCreds != null) {
            if (Arrays.equals(additionalCreds, bindPassword.getValue())) {
                authenticatedDN = bindDN;
                if (controlMap.containsKey(AuthorizationIdentityRequestControl.AUTHORIZATION_IDENTITY_REQUEST_OID)) {
                    responseControls.add(new AuthorizationIdentityResponseControl("dn:" + bindDN.toString()));
                }
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null, null), responseControls);
            } else {
                return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_WRONG_PASSWORD.get(request.getBindDN()), null, null));
            }
        }
        // If the target user doesn't exist, then reject the request.
        final ReadOnlyEntry userEntry = entryMap.get(bindDN);
        if (userEntry == null) {
            return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_NO_SUCH_USER.get(request.getBindDN()), null, null));
        }
        // Get a list of the user's passwords, restricted to those that match the
        // provided clear-text password.  If the list is empty, then the
        // authentication failed.
        final List<InMemoryDirectoryServerPassword> matchingPasswords = getPasswordsInEntry(userEntry, bindPassword);
        if (matchingPasswords.isEmpty()) {
            return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.INVALID_CREDENTIALS_INT_VALUE, null, ERR_MEM_HANDLER_BIND_WRONG_PASSWORD.get(request.getBindDN()), null, null));
        }
        // If we've gotten here, then authentication was successful.
        authenticatedDN = bindDN;
        if (controlMap.containsKey(AuthorizationIdentityRequestControl.AUTHORIZATION_IDENTITY_REQUEST_OID)) {
            responseControls.add(new AuthorizationIdentityResponseControl("dn:" + bindDN.toString()));
        }
        return new LDAPMessage(messageID, new BindResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null, null, null, null), responseControls);
    }
}
Also used : ASN1OctetString(com.unboundid.asn1.ASN1OctetString) AuthorizationIdentityResponseControl(com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl) 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) LDAPException(com.unboundid.ldap.sdk.LDAPException) LDIFException(com.unboundid.ldif.LDIFException) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) BindResponseProtocolOp(com.unboundid.ldap.protocol.BindResponseProtocolOp) 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) LDAPException(com.unboundid.ldap.sdk.LDAPException) BindResult(com.unboundid.ldap.sdk.BindResult) NotNull(com.unboundid.util.NotNull)

Example 7 with ReadOnlyEntry

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

the class InMemoryRequestHandler method getPasswordsInEntry.

/**
 * Retrieves a list of the passwords contained in the provided entry.
 *
 * @param  entry                 The entry from which to obtain the list of
 *                               passwords.  It must not be {@code null}.
 * @param  clearPasswordToMatch  An optional clear-text password that should
 *                               match the values that are returned.  If this
 *                               is {@code null}, then all passwords contained
 *                               in the provided entry will be returned.  If
 *                               this is non-{@code null}, then only passwords
 *                               matching the clear-text password will be
 *                               returned.
 *
 * @return  A list of the passwords contained in the provided entry,
 *          optionally restricted to those matching the provided clear-text
 *          password, or an empty list if the entry does not contain any
 *          passwords.
 */
@NotNull()
public List<InMemoryDirectoryServerPassword> getPasswordsInEntry(@NotNull final Entry entry, @Nullable final ASN1OctetString clearPasswordToMatch) {
    final ArrayList<InMemoryDirectoryServerPassword> passwordList = new ArrayList<>(5);
    final ReadOnlyEntry readOnlyEntry = new ReadOnlyEntry(entry);
    for (final String passwordAttributeName : configuredPasswordAttributes) {
        final List<Attribute> passwordAttributeList = entry.getAttributesWithOptions(passwordAttributeName, null);
        for (final Attribute passwordAttribute : passwordAttributeList) {
            for (final ASN1OctetString value : passwordAttribute.getRawValues()) {
                final InMemoryDirectoryServerPassword password = new InMemoryDirectoryServerPassword(value, readOnlyEntry, passwordAttribute.getName(), passwordEncoders);
                if (clearPasswordToMatch != null) {
                    try {
                        if (!password.matchesClearPassword(clearPasswordToMatch)) {
                            continue;
                        }
                    } catch (final Exception e) {
                        Debug.debugException(e);
                        continue;
                    }
                }
                passwordList.add(new InMemoryDirectoryServerPassword(value, readOnlyEntry, passwordAttribute.getName(), passwordEncoders));
            }
        }
    }
    return passwordList;
}
Also used : ASN1OctetString(com.unboundid.asn1.ASN1OctetString) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) Attribute(com.unboundid.ldap.sdk.Attribute) ArrayList(java.util.ArrayList) ASN1OctetString(com.unboundid.asn1.ASN1OctetString) LDAPException(com.unboundid.ldap.sdk.LDAPException) LDIFException(com.unboundid.ldif.LDIFException) NotNull(com.unboundid.util.NotNull)

Example 8 with ReadOnlyEntry

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

the class InMemoryRequestHandler method generateRootDSE.

/**
 * Generates an entry to use as the server root DSE.
 *
 * @return  The generated root DSE entry.
 */
@NotNull()
private ReadOnlyEntry generateRootDSE() {
    final ReadOnlyEntry rootDSEFromCfg = config.getRootDSEEntry();
    if (rootDSEFromCfg != null) {
        return rootDSEFromCfg;
    }
    final Entry rootDSEEntry = new Entry(DN.NULL_DN, schemaRef.get());
    rootDSEEntry.addAttribute("objectClass", "top", "ds-root-dse");
    rootDSEEntry.addAttribute(new Attribute("supportedLDAPVersion", IntegerMatchingRule.getInstance(), "3"));
    final String vendorName = config.getVendorName();
    if (vendorName != null) {
        rootDSEEntry.addAttribute("vendorName", vendorName);
    }
    final String vendorVersion = config.getVendorVersion();
    if (vendorVersion != null) {
        rootDSEEntry.addAttribute("vendorVersion", vendorVersion);
    }
    rootDSEEntry.addAttribute(new Attribute("subschemaSubentry", DistinguishedNameMatchingRule.getInstance(), subschemaSubentryDN.toString()));
    rootDSEEntry.addAttribute(new Attribute("entryDN", DistinguishedNameMatchingRule.getInstance(), ""));
    rootDSEEntry.addAttribute("entryUUID", CryptoHelper.getRandomUUID().toString());
    rootDSEEntry.addAttribute("supportedFeatures", // All operational attributes
    "1.3.6.1.4.1.4203.1.5.1", // Request attributes by object class
    "1.3.6.1.4.1.4203.1.5.2", // LDAP absolute true and false filters
    "1.3.6.1.4.1.4203.1.5.3", // Increment modification type
    "1.3.6.1.1.14");
    final TreeSet<String> ctlSet = new TreeSet<>();
    ctlSet.add(AssertionRequestControl.ASSERTION_REQUEST_OID);
    ctlSet.add(AuthorizationIdentityRequestControl.AUTHORIZATION_IDENTITY_REQUEST_OID);
    ctlSet.add(DontUseCopyRequestControl.DONT_USE_COPY_REQUEST_OID);
    ctlSet.add(ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID);
    ctlSet.add(DraftLDUPSubentriesRequestControl.SUBENTRIES_REQUEST_OID);
    ctlSet.add(DraftZeilengaLDAPNoOp12RequestControl.NO_OP_REQUEST_OID);
    ctlSet.add(PermissiveModifyRequestControl.PERMISSIVE_MODIFY_REQUEST_OID);
    ctlSet.add(PostReadRequestControl.POST_READ_REQUEST_OID);
    ctlSet.add(PreReadRequestControl.PRE_READ_REQUEST_OID);
    ctlSet.add(ProxiedAuthorizationV1RequestControl.PROXIED_AUTHORIZATION_V1_REQUEST_OID);
    ctlSet.add(ProxiedAuthorizationV2RequestControl.PROXIED_AUTHORIZATION_V2_REQUEST_OID);
    ctlSet.add(RFC3672SubentriesRequestControl.SUBENTRIES_REQUEST_OID);
    ctlSet.add(ServerSideSortRequestControl.SERVER_SIDE_SORT_REQUEST_OID);
    ctlSet.add(SimplePagedResultsControl.PAGED_RESULTS_OID);
    ctlSet.add(SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID);
    ctlSet.add(TransactionSpecificationRequestControl.TRANSACTION_SPECIFICATION_REQUEST_OID);
    ctlSet.add(VirtualListViewRequestControl.VIRTUAL_LIST_VIEW_REQUEST_OID);
    ctlSet.add(IgnoreNoUserModificationRequestControl.IGNORE_NO_USER_MODIFICATION_REQUEST_OID);
    final String[] controlOIDs = new String[ctlSet.size()];
    rootDSEEntry.addAttribute("supportedControl", ctlSet.toArray(controlOIDs));
    if (!extendedRequestHandlers.isEmpty()) {
        final String[] oidArray = new String[extendedRequestHandlers.size()];
        rootDSEEntry.addAttribute("supportedExtension", extendedRequestHandlers.keySet().toArray(oidArray));
        for (final InMemoryListenerConfig c : config.getListenerConfigs()) {
            if (c.getStartTLSSocketFactory() != null) {
                rootDSEEntry.addAttribute("supportedExtension", StartTLSExtendedRequest.STARTTLS_REQUEST_OID);
                break;
            }
        }
    }
    if (!saslBindHandlers.isEmpty()) {
        final String[] mechanismArray = new String[saslBindHandlers.size()];
        rootDSEEntry.addAttribute("supportedSASLMechanisms", saslBindHandlers.keySet().toArray(mechanismArray));
    }
    int pos = 0;
    final String[] baseDNStrings = new String[baseDNs.size()];
    for (final DN baseDN : baseDNs) {
        baseDNStrings[pos++] = baseDN.toString();
    }
    rootDSEEntry.addAttribute(new Attribute("namingContexts", DistinguishedNameMatchingRule.getInstance(), baseDNStrings));
    if (maxChangelogEntries > 0) {
        rootDSEEntry.addAttribute(new Attribute("changeLog", DistinguishedNameMatchingRule.getInstance(), changeLogBaseDN.toString()));
        rootDSEEntry.addAttribute(new Attribute("firstChangeNumber", IntegerMatchingRule.getInstance(), firstChangeNumber.toString()));
        rootDSEEntry.addAttribute(new Attribute("lastChangeNumber", IntegerMatchingRule.getInstance(), lastChangeNumber.toString()));
    }
    for (final Attribute customAttribute : config.getCustomRootDSEAttributes()) {
        rootDSEEntry.setAttribute(customAttribute);
    }
    return new ReadOnlyEntry(rootDSEEntry);
}
Also used : ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) ChangeLogEntry(com.unboundid.ldap.sdk.ChangeLogEntry) SearchResultEntry(com.unboundid.ldap.sdk.SearchResultEntry) Entry(com.unboundid.ldap.sdk.Entry) ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) Attribute(com.unboundid.ldap.sdk.Attribute) TreeSet(java.util.TreeSet) RDN(com.unboundid.ldap.sdk.RDN) DN(com.unboundid.ldap.sdk.DN) ASN1OctetString(com.unboundid.asn1.ASN1OctetString) NotNull(com.unboundid.util.NotNull)

Example 9 with ReadOnlyEntry

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

the class InMemoryRequestHandler method exportToLDIF.

/**
 * Writes all entries contained in the server to LDIF using the provided
 * writer.
 *
 * @param  ldifWriter             The LDIF writer to use when writing the
 *                                entries.  It must not be {@code null}.
 * @param  excludeGeneratedAttrs  Indicates whether to exclude automatically
 *                                generated operational attributes like
 *                                entryUUID, entryDN, creatorsName, etc.
 * @param  excludeChangeLog       Indicates whether to exclude entries
 *                                contained in the changelog.
 * @param  closeWriter            Indicates whether the LDIF writer should be
 *                                closed after all entries have been written.
 *
 * @return  The number of entries written to LDIF.
 *
 * @throws  LDAPException  If a problem is encountered while attempting to
 *                         write an entry to LDIF.
 */
public int exportToLDIF(@NotNull final LDIFWriter ldifWriter, final boolean excludeGeneratedAttrs, final boolean excludeChangeLog, final boolean closeWriter) throws LDAPException {
    synchronized (entryMap) {
        boolean exceptionThrown = false;
        try {
            int entriesWritten = 0;
            for (final Map.Entry<DN, ReadOnlyEntry> me : entryMap.entrySet()) {
                final DN dn = me.getKey();
                if (excludeChangeLog && dn.isDescendantOf(changeLogBaseDN, true)) {
                    continue;
                }
                final Entry entry;
                if (excludeGeneratedAttrs) {
                    entry = me.getValue().duplicate();
                    entry.removeAttribute("entryDN");
                    entry.removeAttribute("entryUUID");
                    entry.removeAttribute("subschemaSubentry");
                    entry.removeAttribute("creatorsName");
                    entry.removeAttribute("createTimestamp");
                    entry.removeAttribute("modifiersName");
                    entry.removeAttribute("modifyTimestamp");
                } else {
                    entry = me.getValue();
                }
                try {
                    ldifWriter.writeEntry(entry);
                    entriesWritten++;
                } catch (final Exception e) {
                    Debug.debugException(e);
                    exceptionThrown = true;
                    throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MEM_HANDLER_LDIF_WRITE_ERROR.get(entry.getDN(), StaticUtils.getExceptionMessage(e)), e);
                }
            }
            return entriesWritten;
        } finally {
            if (closeWriter) {
                try {
                    ldifWriter.close();
                } catch (final Exception e) {
                    Debug.debugException(e);
                    if (!exceptionThrown) {
                        throw new LDAPException(ResultCode.LOCAL_ERROR, ERR_MEM_HANDLER_LDIF_WRITE_CLOSE_ERROR.get(StaticUtils.getExceptionMessage(e)), e);
                    }
                }
            }
        }
    }
}
Also used : ReadOnlyEntry(com.unboundid.ldap.sdk.ReadOnlyEntry) 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) RDN(com.unboundid.ldap.sdk.RDN) DN(com.unboundid.ldap.sdk.DN) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) TreeMap(java.util.TreeMap) HashMap(java.util.HashMap) LDAPException(com.unboundid.ldap.sdk.LDAPException) LDIFException(com.unboundid.ldif.LDIFException)

Example 10 with ReadOnlyEntry

use of com.unboundid.ldap.sdk.ReadOnlyEntry 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)

Aggregations

ReadOnlyEntry (com.unboundid.ldap.sdk.ReadOnlyEntry)94 Test (org.testng.annotations.Test)64 ASN1OctetString (com.unboundid.asn1.ASN1OctetString)41 Entry (com.unboundid.ldap.sdk.Entry)29 DN (com.unboundid.ldap.sdk.DN)27 Attribute (com.unboundid.ldap.sdk.Attribute)25 Modification (com.unboundid.ldap.sdk.Modification)21 LDAPException (com.unboundid.ldap.sdk.LDAPException)18 ChangeLogEntry (com.unboundid.ldap.sdk.ChangeLogEntry)16 Control (com.unboundid.ldap.sdk.Control)14 SearchResultEntry (com.unboundid.ldap.sdk.SearchResultEntry)14 NotNull (com.unboundid.util.NotNull)14 RDN (com.unboundid.ldap.sdk.RDN)12 ArrayList (java.util.ArrayList)12 LDAPResult (com.unboundid.ldap.sdk.LDAPResult)9 PostReadResponseControl (com.unboundid.ldap.sdk.controls.PostReadResponseControl)8 PreReadResponseControl (com.unboundid.ldap.sdk.controls.PreReadResponseControl)8 Schema (com.unboundid.ldap.sdk.schema.Schema)8 AuthorizationIdentityResponseControl (com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl)7 ServerSideSortResponseControl (com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl)7