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);
}
}
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;
}
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);
}
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);
}
}
}
}
}
}
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));
}
}
Aggregations