/** * Evaluate an entry to be added to see if it has any "aci" attribute type. If it does, examines * each "aci" attribute type value for syntax errors. All of the "aci" attribute type values must * pass syntax check for the add operation to proceed. Any entry with an "aci" attribute type must * have "modify-acl" privileges. * * @param entry The entry to be examined. * @param operation The operation to to check privileges on. * @param clientDN The authorization DN. * @return True if the entry has no ACI attributes or if all of the "aci" attributes values pass * ACI syntax checking. * @throws DirectoryException If a modified ACI could not be decoded. */ private boolean verifySyntax(Entry entry, Operation operation, DN clientDN) throws DirectoryException { if (entry.hasOperationalAttribute(aciType)) { /* * Check that the operation has "modify-acl" privileges since the * entry to be added has an "aci" attribute type. */ if (!operation.getClientConnection().hasPrivilege(Privilege.MODIFY_ACL, operation)) { Message message = INFO_ACI_ADD_FAILED_PRIVILEGE.get( String.valueOf(entry.getDN()), String.valueOf(clientDN)); logError(message); return false; } List<Attribute> attributeList = entry.getOperationalAttribute(aciType, null); for (Attribute attribute : attributeList) { for (AttributeValue value : attribute) { try { DN dn = entry.getDN(); Aci.decode(value.getValue(), dn); } catch (AciException ex) { Message message = WARN_ACI_ADD_FAILED_DECODE.get(String.valueOf(entry.getDN()), ex.getMessage()); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } } } } return true; }
/** * A utility method which may be used by implementations in order to obtain the value of the * specified attribute from the provided entry as a boolean. * * @param entry The entry whose attribute is to be parsed as a boolean. * @param attributeType The attribute type whose value should be parsed as a boolean. * @return The attribute's value represented as a ConditionResult value, or * ConditionResult.UNDEFINED if the specified attribute does not exist in the entry. * @throws DirectoryException If the value cannot be decoded as a boolean. */ protected static final ConditionResult getBoolean( final Entry entry, final AttributeType attributeType) throws DirectoryException { final List<Attribute> attrList = entry.getAttribute(attributeType); if (attrList != null) { for (final Attribute a : attrList) { if (a.isEmpty()) { continue; } final String valueString = toLowerCase(a.iterator().next().getValue().toString()); if (valueString.equals("true") || valueString.equals("yes") || valueString.equals("on") || valueString.equals("1")) { if (debugEnabled()) { TRACER.debugInfo( "Attribute %s resolves to true for user entry " + "%s", attributeType.getNameOrOID(), entry.getDN().toString()); } return ConditionResult.TRUE; } if (valueString.equals("false") || valueString.equals("no") || valueString.equals("off") || valueString.equals("0")) { if (debugEnabled()) { TRACER.debugInfo( "Attribute %s resolves to false for user " + "entry %s", attributeType.getNameOrOID(), entry.getDN().toString()); } return ConditionResult.FALSE; } if (debugEnabled()) { TRACER.debugError( "Unable to resolve value %s for attribute %s " + "in user entry %s as a Boolean.", valueString, attributeType.getNameOrOID(), entry.getDN().toString()); } final Message message = ERR_PWPSTATE_CANNOT_DECODE_BOOLEAN.get( valueString, attributeType.getNameOrOID(), entry.getDN().toString()); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } } if (debugEnabled()) { TRACER.debugInfo( "Returning %s because attribute %s does not exist " + "in user entry %s", ConditionResult.UNDEFINED.toString(), attributeType.getNameOrOID(), entry.getDN().toString()); } return ConditionResult.UNDEFINED; }
/** {@inheritDoc} */ @Override() public DynamicGroup newInstance(Entry groupEntry) throws DirectoryException { ensureNotNull(groupEntry); // Get the memberURL attribute from the entry, if there is one, and parse // out the LDAP URLs that it contains. LinkedHashSet<LDAPURL> memberURLs = new LinkedHashSet<LDAPURL>(); AttributeType memberURLType = DirectoryConfig.getAttributeType(ATTR_MEMBER_URL_LC, true); List<Attribute> attrList = groupEntry.getAttribute(memberURLType); if (attrList != null) { for (Attribute a : attrList) { for (AttributeValue v : a) { try { memberURLs.add(LDAPURL.decode(v.getValue().toString(), true)); } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } Message message = ERR_DYNAMICGROUP_CANNOT_DECODE_MEMBERURL.get( v.getValue().toString(), String.valueOf(groupEntry.getDN()), de.getMessageObject()); ErrorLogger.logError(message); } } } } return new DynamicGroup(groupEntry.getDN(), memberURLs); }
/** * Test entry. * * @throws Exception If the test failed unexpectedly. */ @Test() public void testEntryToAndFromDatabase() throws Exception { // Make sure that the server is up and running. TestCaseUtils.startServer(); // Convert the test LDIF string to a byte array byte[] originalLDIFBytes = StaticUtils.getBytes(ldifString); LDIFReader reader = new LDIFReader(new LDIFImportConfig(new ByteArrayInputStream(originalLDIFBytes))); Entry entryBefore, entryAfter; while ((entryBefore = reader.readEntry(false)) != null) { ByteString bytes = ID2Entry.entryToDatabase(entryBefore, new DataConfig(false, false, null)); entryAfter = ID2Entry.entryFromDatabase(bytes, DirectoryServer.getDefaultCompressedSchema()); // check DN and number of attributes assertEquals(entryBefore.getAttributes().size(), entryAfter.getAttributes().size()); assertEquals(entryBefore.getDN(), entryAfter.getDN()); // check the object classes were not changed for (String ocBefore : entryBefore.getObjectClasses().values()) { ObjectClass objectClass = DirectoryServer.getObjectClass(ocBefore.toLowerCase()); if (objectClass == null) { objectClass = DirectoryServer.getDefaultObjectClass(ocBefore); } String ocAfter = entryAfter.getObjectClasses().get(objectClass); assertEquals(ocBefore, ocAfter); } // check the user attributes were not changed for (AttributeType attrType : entryBefore.getUserAttributes().keySet()) { List<Attribute> listBefore = entryBefore.getAttribute(attrType); List<Attribute> listAfter = entryAfter.getAttribute(attrType); assertTrue(listAfter != null); assertEquals(listBefore.size(), listAfter.size()); for (Attribute attrBefore : listBefore) { boolean found = false; for (Attribute attrAfter : listAfter) { if (attrAfter.optionsEqual(attrBefore.getOptions())) { // Found the corresponding attribute assertEquals(attrBefore, attrAfter); found = true; } } assertTrue(found); } } } reader.close(); }
/** * Ensures that password policy creation will fail when given an invalid configuration. * * @param e The entry containing an invalid password policy configuration. * @throws Exception If an unexpected problem occurs. */ @Test(dataProvider = "invalidConfigs") public void testInvalidConfigurations(Entry e) throws Exception { InternalClientConnection connection = InternalClientConnection.getRootConnection(); AddOperation addOperation = connection.processAdd( e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertTrue(addOperation.getResultCode() != ResultCode.SUCCESS); assertNull(DirectoryServer.getEntry(e.getDN())); }
/** * A utility method which may be used by implementations in order to obtain the value of the * specified attribute from the provided entry as a time in generalized time format. * * @param entry The entry whose attribute is to be parsed as a boolean. * @param attributeType The attribute type whose value should be parsed as a generalized time * value. * @return The requested time, or -1 if it could not be determined. * @throws DirectoryException If a problem occurs while attempting to decode the value as a * generalized time. */ protected static final long getGeneralizedTime( final Entry entry, final AttributeType attributeType) throws DirectoryException { long timeValue = -1; final List<Attribute> attrList = entry.getAttribute(attributeType); if (attrList != null) { for (final Attribute a : attrList) { if (a.isEmpty()) { continue; } final AttributeValue v = a.iterator().next(); try { timeValue = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(v.getNormalizedValue()); } catch (final Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); TRACER.debugWarning( "Unable to decode value %s for attribute %s " + "in user entry %s: %s", v.getValue().toString(), attributeType.getNameOrOID(), entry.getDN().toString(), stackTraceToSingleLineString(e)); } final Message message = ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME.get( v.getValue().toString(), attributeType.getNameOrOID(), entry.getDN().toString(), String.valueOf(e)); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, e); } break; } } if (timeValue == -1) { if (debugEnabled()) { TRACER.debugInfo( "Returning -1 because attribute %s does not " + "exist in user entry %s", attributeType.getNameOrOID(), entry.getDN().toString()); } } // FIXME: else to be consistent... return timeValue; }
/** {@inheritDoc} */ @Override() public boolean hasValue(Entry entry, VirtualAttributeRule rule) { Backend backend = DirectoryServer.getBackend(entry.getDN()); try { ConditionResult ret = backend.hasSubordinates(entry.getDN()); return ret != null && ret != ConditionResult.UNDEFINED; } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } return false; } }
/** * Attempt to read a single entry. * * @throws Exception If the test failed unexpectedly. */ @Test(dependsOnMethods = {"testReadEntryEmptyStream"}) public void testReadEntrySingle() throws Exception { final String ldifString = "dn: cn=john, dc=foo, dc=com\n" + "objectClass: top\n" + "objectClass: person\n" + "cn: john\n" + "sn: smith\n"; LDIFReader reader = createLDIFReader(ldifString); try { Entry entry = reader.readEntry(); Assert.assertNotNull(entry); Assert.assertEquals(entry.getDN(), DN.decode("cn=john, dc=foo, dc=com")); Assert.assertTrue(entry.hasObjectClass(OC_TOP)); Assert.assertTrue(entry.hasObjectClass(OC_PERSON)); Assert.assertTrue(entry.hasValue(AT_CN, null, AttributeValues.create(AT_CN, "john"))); Assert.assertTrue(entry.hasValue(AT_SN, null, AttributeValues.create(AT_SN, "smith"))); Assert.assertNull(reader.readEntry()); Assert.assertEquals(reader.getEntriesIgnored(), 0); Assert.assertEquals(reader.getEntriesRead(), 1); Assert.assertEquals(reader.getEntriesRejected(), 0); Assert.assertEquals(reader.getLastEntryLineNumber(), 1); } finally { reader.close(); } }
/** {@inheritDoc} */ @Override() public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation) throws DirectoryException, CanceledOperationException { checkDiskSpace(modifyOperation); writerBegin(); DN entryDN = newEntry.getDN(); EntryContainer ec; if (rootContainer != null) { ec = rootContainer.getEntryContainer(entryDN); } else { Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); } ec.sharedLock.lock(); try { ec.replaceEntry(oldEntry, newEntry, modifyOperation); } catch (DatabaseException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } throw createDirectoryException(e); } finally { ec.sharedLock.unlock(); writerEnd(); } }
/** * Encodes this entry using the V3 encoding. * * @param buffer The buffer to encode into. * @throws DirectoryException If a problem occurs while attempting to encode the entry. */ private void encodeV1(Entry entry, ByteStringBuilder buffer) throws DirectoryException { // The version number will be one byte. buffer.append((byte) 0x01); // TODO: Can we encode the DN directly into buffer? byte[] dnBytes = getBytes(entry.getDN().toString()); buffer.appendBERLength(dnBytes.length); buffer.append(dnBytes); // Encode number of OCs and 0 terminated names. int i = 1; ByteStringBuilder bsb = new ByteStringBuilder(); for (String ocName : entry.getObjectClasses().values()) { bsb.append(ocName); if (i < entry.getObjectClasses().values().size()) { bsb.append((byte) 0x00); } i++; } buffer.appendBERLength(bsb.length()); buffer.append(bsb); // Encode the user attributes in the appropriate manner. encodeV1Attributes(buffer, entry.getUserAttributes()); // The operational attributes will be encoded in the same way as // the user attributes. encodeV1Attributes(buffer, entry.getOperationalAttributes()); }
/** {@inheritDoc} */ @Override public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation) throws DirectoryException { throw new DirectoryException( ResultCode.UNWILLING_TO_PERFORM, ERR_BACKEND_MODIFY_NOT_SUPPORTED.get(String.valueOf(oldEntry.getDN()), getBackendID())); }
/** * Tests the use of the StartTLS extended operation to communicate with the server in conjunction * with SASL EXTERNAL authentication and using a client trust store to validate the server * certificate. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testStartTLSExternalAuthTrustStore() throws Exception { TestCaseUtils.initializeTestBackend(true); Entry e = TestCaseUtils.makeEntry( "dn: cn=Test User,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "cn: Test User", "givenName: Test", "sn: User"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); AddOperation addOperation = conn.processAdd( e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; String[] args = { "--noPropertiesFile", "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-q", "-K", keyStorePath, "-W", "password", "-P", trustStorePath, "-r", "-b", "", "-s", "base", "(objectClass=*)" }; assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); }
/** {@inheritDoc} */ @Override() public Set<AttributeValue> getValues(Entry entry, VirtualAttributeRule rule) { Backend backend = DirectoryServer.getBackend(entry.getDN()); try { ConditionResult ret = backend.hasSubordinates(entry.getDN()); if (ret != null && ret != ConditionResult.UNDEFINED) { AttributeValue value = AttributeValues.create( ByteString.valueOf(ret.toString()), ByteString.valueOf(ret.toString())); return Collections.singleton(value); } } catch (DirectoryException de) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, de); } } return Collections.emptySet(); }
/** {@inheritDoc} */ @Override public boolean mayProxy(Entry proxyUser, Entry proxiedUser, Operation op) { boolean ret; if (!(ret = skipAccessCheck(proxyUser))) { AuthenticationInfo authInfo = new AuthenticationInfo(proxyUser, DirectoryServer.isRootDN(proxyUser.getDN())); AciLDAPOperationContainer operationContainer = new AciLDAPOperationContainer(op, proxiedUser, authInfo, ACI_PROXY); ret = accessAllowedEntry(operationContainer); } return ret; }
/** * Returns {@code true} if this authentication policy state is associated with a user whose * account has been administratively disabled. * * <p>The default implementation is use the value of the "ds-pwp-account-disable" attribute in the * user's entry. * * @return {@code true} if this authentication policy state is associated with a user whose * account has been administratively disabled. */ public boolean isDisabled() { final AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_DISABLED, true); try { isDisabled = getBoolean(userEntry, type); } catch (final Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } isDisabled = ConditionResult.TRUE; if (debugEnabled()) { TRACER.debugWarning( "User %s is considered administratively " + "disabled because an error occurred while " + "attempting to make the determination: %s.", userEntry.getDN().toString(), stackTraceToSingleLineString(e)); } return true; } if (isDisabled == ConditionResult.UNDEFINED) { isDisabled = ConditionResult.FALSE; if (debugEnabled()) { TRACER.debugInfo( "User %s is not administratively disabled since " + "the attribute \"%s\" is not present in the entry.", userEntry.getDN().toString(), OP_ATTR_ACCOUNT_DISABLED); } return false; } if (debugEnabled()) { TRACER.debugInfo( "User %s %s administratively disabled.", userEntry.getDN().toString(), ((isDisabled == ConditionResult.TRUE) ? " is" : " is not")); } return isDisabled == ConditionResult.TRUE; }
@BeforeClass() public void setUp() throws Exception { TestCaseUtils.startServer(); TestCaseUtils.clearJEBackend(false, "userRoot", SUFFIX); InternalClientConnection connection = InternalClientConnection.getRootConnection(); // Add suffix entry. DN suffixDN = DN.decode(SUFFIX); if (DirectoryServer.getEntry(suffixDN) == null) { Entry suffixEntry = StaticUtils.createEntry(suffixDN); AddOperation addOperation = connection.processAdd( suffixEntry.getDN(), suffixEntry.getObjectClasses(), suffixEntry.getUserAttributes(), suffixEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(suffixEntry.getDN())); } // Add base entry. DN baseDN = DN.decode(BASE); if (DirectoryServer.getEntry(baseDN) == null) { Entry baseEntry = StaticUtils.createEntry(baseDN); AddOperation addOperation = connection.processAdd( baseEntry.getDN(), baseEntry.getObjectClasses(), baseEntry.getUserAttributes(), baseEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(baseEntry.getDN())); } // Add test entry. Entry testEntry = TestCaseUtils.makeEntry( "dn: uid=rogasawara," + BASE, "objectclass: top", "objectclass: person", "objectclass: organizationalPerson", "objectclass: inetOrgPerson", "uid: rogasawara", "userpassword: password", "mail: [email protected]", "givenname: Rodney", "sn: Ogasawara", "cn: Rodney Ogasawara", "title: Sales, Director"); AddOperation addOperation = connection.processAdd( testEntry.getDN(), testEntry.getObjectClasses(), testEntry.getUserAttributes(), testEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(testEntry.getDN())); }
/** * Performs a successful LDAP bind using CRAM-MD5 using the dn: form of the authentication ID * using a long password (longer than 64 bytes). * * @throws Exception If an unexpected problem occurs. */ @Test() public void testLDAPBindSuccessWithDNAndLongPassword() throws Exception { TestCaseUtils.initializeTestBackend(true); String password = "******"; Entry e = TestCaseUtils.makeEntry( "dn: uid=test.user,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.user", "givenName: Test", "sn: User", "cn: Test User", "userPassword: "******"ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); AddOperation addOperation = conn.processAdd( e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); String[] args = { "--noPropertiesFile", "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-o", "mech=CRAM-MD5", "-o", "authid=dn:uid=test.user,o=test", "-w", password, "-b", "", "-s", "base", "(objectClass=*)" }; assertEquals(LDAPSearch.mainSearch(args, false, null, System.err), 0); }
/** * Performs a failed LDAP bind using CRAM-MD5 using the dn: form of the authentication ID with the * DN of a user that doesn't exist. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testLDAPBindFailNoSuchUser() throws Exception { TestCaseUtils.initializeTestBackend(true); Entry e = TestCaseUtils.makeEntry( "dn: uid=test.user,o=test", "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.user", "givenName: Test", "sn: User", "cn: Test User", "userPassword: password"); InternalClientConnection conn = InternalClientConnection.getRootConnection(); AddOperation addOperation = conn.processAdd( e.getDN(), e.getObjectClasses(), e.getUserAttributes(), e.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); String[] args = { "--noPropertiesFile", "-h", "127.0.0.1", "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), "-o", "mech=CRAM-MD5", "-o", "authid=dn:uid=doesntexist,o=test", "-w", "password", "-b", "", "-s", "base", "(objectClass=*)" }; assertFalse(LDAPSearch.mainSearch(args, false, null, null) == 0); }
/** * Encodes this entry using the V3 encoding. * * @param buffer The buffer to encode into. * @throws DirectoryException If a problem occurs while attempting to encode the entry. */ private void encodeV2(Entry entry, ByteStringBuilder buffer, EntryEncodeConfig config) throws DirectoryException { // The version number will be one byte. buffer.append((byte) 0x02); // Get the encoded respresentation of the config. config.encode(buffer); // If we should include the DN, then it will be encoded as a // one-to-five byte length followed by the UTF-8 byte // representation. if (!config.excludeDN()) { // TODO: Can we encode the DN directly into buffer? byte[] dnBytes = getBytes(entry.getDN().toString()); buffer.appendBERLength(dnBytes.length); buffer.append(dnBytes); } // Encode the object classes in the appropriate manner. if (config.compressObjectClassSets()) { config.getCompressedSchema().encodeObjectClasses(buffer, entry.getObjectClasses()); } else { // Encode number of OCs and 0 terminated names. int i = 1; ByteStringBuilder bsb = new ByteStringBuilder(); for (String ocName : entry.getObjectClasses().values()) { bsb.append(ocName); if (i < entry.getObjectClasses().values().size()) { bsb.append((byte) 0x00); } i++; } buffer.appendBERLength(bsb.length()); buffer.append(bsb); } // Encode the user attributes in the appropriate manner. encodeV2Attributes(buffer, entry.getUserAttributes(), config); // The operational attributes will be encoded in the same way as // the user attributes. encodeV2Attributes(buffer, entry.getOperationalAttributes(), config); }
/** * Tests the entry encoding and decoding process the version 1 encoding. * * @throws Exception If the test failed unexpectedly. */ @Test(dataProvider = "encodeConfigs") public void testEntryToAndFromDatabaseV3(EntryEncodeConfig config) throws Exception { // Make sure that the server is up and running. TestCaseUtils.startServer(); // Convert the test LDIF string to a byte array byte[] originalLDIFBytes = StaticUtils.getBytes(ldifString); LDIFReader reader = new LDIFReader(new LDIFImportConfig(new ByteArrayInputStream(originalLDIFBytes))); Entry entryBefore, entryAfterV3; while ((entryBefore = reader.readEntry(false)) != null) { ByteStringBuilder bsb = new ByteStringBuilder(); entryBefore.encode(bsb, config); entryAfterV3 = Entry.decode(bsb.asReader()); if (config.excludeDN()) { entryAfterV3.setDN(entryBefore.getDN()); } assertEquals(entryBefore, entryAfterV3); } reader.close(); }
/** {@inheritDoc} */ @Override() public void renameEntry(DN currentDN, Entry entry, ModifyDNOperation modifyDNOperation) throws DirectoryException, CanceledOperationException { checkDiskSpace(modifyDNOperation); writerBegin(); EntryContainer currentContainer; if (rootContainer != null) { currentContainer = rootContainer.getEntryContainer(currentDN); } else { Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID()); throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); } EntryContainer container = rootContainer.getEntryContainer(entry.getDN()); if (currentContainer != container) { // FIXME: No reason why we cannot implement a move between containers // since the containers share the same database environment. Message msg = WARN_JEB_FUNCTION_NOT_SUPPORTED.get(); throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg); } currentContainer.sharedLock.lock(); try { currentContainer.renameEntry(currentDN, entry, modifyDNOperation); } catch (DatabaseException e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } throw createDirectoryException(e); } finally { currentContainer.sharedLock.unlock(); writerEnd(); } }
/** * Tests performing an internal search using the VLV control with a start start position beyond * the end of the result set. * * @throws Exception If an unexpected problem occurred. */ @Test() public void testInternalSearchByOffsetStartPositionTooHigh() throws Exception { populateDB(); InternalClientConnection conn = InternalClientConnection.getRootConnection(); ArrayList<Control> requestControls = new ArrayList<Control>(); requestControls.add(new ServerSideSortRequestControl("givenName")); requestControls.add(new VLVRequestControl(3, 3, 30, 0)); InternalSearchOperation internalSearch = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), requestControls, DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, SearchFilter.createFilterFromString("(objectClass=person)"), null, null); internalSearch.run(); assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); expectedDNOrder.add(maryJonesDN); // Mary expectedDNOrder.add(samZweckDN); // Sam expectedDNOrder.add(zorroDN); // No first name ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); for (Entry e : internalSearch.getSearchEntries()) { returnedDNOrder.add(e.getDN()); } assertEquals(returnedDNOrder, expectedDNOrder); List<Control> responseControls = internalSearch.getResponseControls(); assertNotNull(responseControls); VLVResponseControl vlvResponse = null; for (Control c : responseControls) { if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) { if (c instanceof LDAPControl) { vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl) c).getValue()); } else { vlvResponse = (VLVResponseControl) c; } } } assertNotNull(vlvResponse); assertEquals(vlvResponse.getVLVResultCode(), LDAPResultCode.SUCCESS); assertEquals(vlvResponse.getTargetPosition(), 10); assertEquals(vlvResponse.getContentCount(), 9); }
/** * Ensures that password policy pwdPolicySubentry operational attribute reflects active password * policy for a given user entry. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testPasswordPolicySubentryAttribute() throws Exception { PasswordPolicy defaultPolicy = DirectoryServer.getDefaultPasswordPolicy(); assertNotNull(defaultPolicy); Entry testEntry = DirectoryServer.getEntry(DN.decode("uid=rogasawara," + BASE)); assertNotNull(testEntry); AttributeType attrType = DirectoryServer.getAttributeType("pwdpolicysubentry"); // Make sure that default policy is in effect // for the user entry. assertTrue(testEntry.hasAttribute(attrType)); assertTrue( testEntry.hasValue( attrType, null, AttributeValues.create(attrType, defaultPolicy.getDN().toString()))); // Add new subentry policy with the // scope to apply to the user entry. Entry policyEntry = TestCaseUtils.makeEntry( "dn: cn=Temp Policy," + SUFFIX, "objectClass: top", "objectClass: pwdPolicy", "objectClass: subentry", "cn: Temp Policy", "subtreeSpecification: { base \"ou=people\" }", "pwdLockoutDuration: 300", "pwdMaxFailure: 3", "pwdMustChange: true", "pwdAttribute: userPassword"); InternalClientConnection connection = InternalClientConnection.getRootConnection(); AddOperation addOperation = connection.processAdd( policyEntry.getDN(), policyEntry.getObjectClasses(), policyEntry.getUserAttributes(), policyEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(policyEntry.getDN())); // Make sure just added policy is in effect. testEntry = DirectoryServer.getEntry(DN.decode("uid=rogasawara," + BASE)); assertNotNull(testEntry); assertTrue(testEntry.hasAttribute(attrType)); assertTrue( testEntry.hasValue( attrType, null, AttributeValues.create(attrType, "cn=Temp Policy," + SUFFIX))); // Remove subentry policy and make sure // default policy is in effect again. TestCaseUtils.deleteEntry(policyEntry.getDN()); testEntry = DirectoryServer.getEntry(DN.decode("uid=rogasawara," + BASE)); assertNotNull(testEntry); assertTrue(testEntry.hasAttribute(attrType)); assertTrue( testEntry.hasValue( attrType, null, AttributeValues.create(attrType, defaultPolicy.getDN().toString()))); }
/** * Ensures that password policy constructed from subentry is active and has a valid configuration. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testValidConfiguration() throws Exception { PasswordPolicy defaultPolicy = DirectoryServer.getDefaultPasswordPolicy(); assertNotNull(defaultPolicy); // The values are selected on a basis that they // should differ from default password policy. Entry policyEntry = TestCaseUtils.makeEntry( "dn: cn=Temp Policy," + SUFFIX, "objectClass: top", "objectClass: pwdPolicy", "objectClass: subentry", "cn: Temp Policy", "subtreeSpecification: { base \"ou=people\" }", "pwdLockoutDuration: 300", "pwdMaxFailure: 3", "pwdMustChange: TRUE", "pwdAttribute: authPassword", "pwdMinAge: 600", "pwdMaxAge: 2147483647", "pwdInHistory: 5", "pwdExpireWarning: 864000", "pwdGraceAuthNLimit: 3", "pwdFailureCountInterval: 3600", "pwdAllowUserChange: FALSE", "pwdSafeModify: TRUE"); InternalClientConnection connection = InternalClientConnection.getRootConnection(); AddOperation addOperation = connection.processAdd( policyEntry.getDN(), policyEntry.getObjectClasses(), policyEntry.getUserAttributes(), policyEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(policyEntry.getDN())); PasswordPolicy policy = (PasswordPolicy) DirectoryServer.getAuthenticationPolicy(DN.decode("cn=Temp Policy," + SUFFIX)); assertNotNull(policy); // Check all pwp attributes for correct values. assertEquals(policy.getLockoutDuration(), 300); assertEquals(policy.getLockoutFailureCount(), 3); assertEquals(policy.isForceChangeOnReset(), true); assertTrue(policy.getPasswordAttribute().getPrimaryName().equalsIgnoreCase("authPassword")); assertEquals(policy.getMinPasswordAge(), 600); assertEquals(policy.getMaxPasswordAge(), 2147483647); assertEquals(policy.getPasswordHistoryCount(), 5); assertEquals(policy.getPasswordExpirationWarningInterval(), 864000); assertEquals(policy.getGraceLoginCount(), 3); assertEquals(policy.getLockoutFailureExpirationInterval(), 3600); assertEquals(policy.isAllowUserPasswordChanges(), false); assertEquals(policy.isPasswordChangeRequiresCurrentPassword(), true); /* Check the password validator attributes for correct values. * The default unit-test config has a single Password validator which is * enabled for the default password policy. */ Collection<PasswordValidator<?>> validators = policy.getPasswordValidators(); assertEquals(validators.size(), 1); for (PasswordValidator<?> validator : validators) { assertTrue( validator.toString().startsWith("org.opends.server.extensions.TestPasswordValidator")); } // Make sure this policy applies to the test entry // its supposed to target and that its the same // policy object as previously tested. Entry testEntry = DirectoryServer.getEntry(DN.decode("uid=rogasawara," + BASE)); assertNotNull(testEntry); AuthenticationPolicy statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(policy, statePolicy); // Make sure this policy is gone and default // policy is in effect instead. TestCaseUtils.deleteEntry(policyEntry.getDN()); statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(defaultPolicy, statePolicy); }
/** * Checks to see if a LDAP modification is allowed access. * * @param container The structure containing the LDAP modifications * @param operation The operation to check modify privileges on. operation to check and the * evaluation context to apply the check against. * @param skipAccessCheck True if access checking should be skipped. * @return True if access is allowed. * @throws DirectoryException If a modified ACI could not be decoded. */ private boolean aciCheckMods( AciLDAPOperationContainer container, LocalBackendModifyOperation operation, boolean skipAccessCheck) throws DirectoryException { Entry resourceEntry = container.getResourceEntry(); DN dn = resourceEntry.getDN(); List<Modification> modifications = operation.getModifications(); for (Modification m : modifications) { Attribute modAttr = m.getAttribute(); AttributeType modAttrType = modAttr.getAttributeType(); if (modAttrType.equals(aciType)) { /* * Check that the operation has modify privileges if it contains * an "aci" attribute type. */ if (!operation.getClientConnection().hasPrivilege(Privilege.MODIFY_ACL, operation)) { Message message = INFO_ACI_MODIFY_FAILED_PRIVILEGE.get( String.valueOf(container.getResourceDN()), String.valueOf(container.getClientDN())); logError(message); return false; } } // This access check handles the case where all attributes of this // type are being replaced or deleted. If only a subset is being // deleted than this access check is skipped. ModificationType modType = m.getModificationType(); if (((modType == ModificationType.DELETE) && modAttr.isEmpty()) || ((modType == ModificationType.REPLACE) || (modType == ModificationType.INCREMENT))) { /* * Check if we have rights to delete all values of an attribute * type in the resource entry. */ if (resourceEntry.hasAttribute(modAttrType)) { container.setCurrentAttributeType(modAttrType); List<Attribute> attrList = resourceEntry.getAttribute(modAttrType, modAttr.getOptions()); if (attrList != null) { for (Attribute a : attrList) { for (AttributeValue v : a) { container.setCurrentAttributeValue(v); container.setRights(ACI_WRITE_DELETE); if (!skipAccessCheck && !accessAllowed(container)) { return false; } } } } } } if (!modAttr.isEmpty()) { for (AttributeValue v : modAttr) { container.setCurrentAttributeType(modAttrType); switch (m.getModificationType()) { case ADD: case REPLACE: container.setCurrentAttributeValue(v); container.setRights(ACI_WRITE_ADD); if (!skipAccessCheck && !accessAllowed(container)) { return false; } break; case DELETE: container.setCurrentAttributeValue(v); container.setRights(ACI_WRITE_DELETE); if (!skipAccessCheck && !accessAllowed(container)) { return false; } break; case INCREMENT: Entry modifiedEntry = operation.getModifiedEntry(); List<Attribute> modifiedAttrs = modifiedEntry.getAttribute(modAttrType, modAttr.getOptions()); if (modifiedAttrs != null) { for (Attribute attr : modifiedAttrs) { for (AttributeValue val : attr) { container.setCurrentAttributeValue(val); container.setRights(ACI_WRITE_ADD); if (!skipAccessCheck && !accessAllowed(container)) { return false; } } } } break; } /* * Check if the modification type has an "aci" attribute type. * If so, check the syntax of that attribute value. Fail the * the operation if the syntax check fails. */ if (modAttrType.equals(aciType) || modAttrType.equals(globalAciType)) { try { // A global ACI needs a NULL DN, not the DN of the // modification. if (modAttrType.equals(globalAciType)) { dn = DN.nullDN(); } Aci.decode(v.getValue(), dn); } catch (AciException ex) { Message message = WARN_ACI_MODIFY_FAILED_DECODE.get(String.valueOf(dn), ex.getMessage()); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } } } } } return true; }
/** * Ensures that password policy constructed from subentry, containing a password validator * reference, is active and has a valid configuration. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testValidConfigurationWithValidator() throws Exception { PasswordPolicy defaultPolicy = DirectoryServer.getDefaultPasswordPolicy(); assertNotNull(defaultPolicy); // The values are selected on a basis that they // should differ from default password policy. Entry policyEntry = TestCaseUtils.makeEntry( "dn: cn=Temp Validator Policy," + SUFFIX, "objectClass: top", "objectClass: pwdPolicy", "objectClass: pwdValidatorPolicy", "objectClass: subentry", "cn: Temp Policy", "subtreeSpecification: { base \"ou=people\" }", "pwdLockoutDuration: 300", "pwdMaxFailure: 3", "pwdMustChange: TRUE", "pwdAttribute: authPassword", "pwdMinAge: 600", "pwdMaxAge: 2147483647", "pwdInHistory: 5", "pwdExpireWarning: 864000", "pwdGraceAuthNLimit: 3", "pwdFailureCountInterval: 3600", "pwdAllowUserChange: FALSE", "pwdSafeModify: TRUE", "ds-cfg-password-validator: cn=Unique Characters,cn=Password Validators,cn=config", "ds-cfg-password-validator: cn=Length-Based Password Validator,cn=Password Validators,cn=config"); InternalClientConnection connection = InternalClientConnection.getRootConnection(); AddOperation addOperation = connection.processAdd( policyEntry.getDN(), policyEntry.getObjectClasses(), policyEntry.getUserAttributes(), policyEntry.getOperationalAttributes()); assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); assertNotNull(DirectoryServer.getEntry(policyEntry.getDN())); PasswordPolicy policy = (PasswordPolicy) DirectoryServer.getAuthenticationPolicy( DN.decode("cn=Temp Validator Policy," + SUFFIX)); assertNotNull(policy); // Check the password validator attributes for correct values. Collection<PasswordValidator<?>> validators = policy.getPasswordValidators(); assertFalse(validators.isEmpty()); assertEquals(validators.size(), 2); // Make sure this policy applies to the test entry // its supposed to target and that its the same // policy object as previously tested. Entry testEntry = DirectoryServer.getEntry(DN.decode("uid=rogasawara," + BASE)); assertNotNull(testEntry); AuthenticationPolicy statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(policy, statePolicy); // Make sure this policy is gone and default // policy is in effect instead. TestCaseUtils.deleteEntry(policyEntry.getDN()); statePolicy = AuthenticationPolicy.forUser(testEntry, false); assertNotNull(statePolicy); assertEquals(defaultPolicy, statePolicy); }
private DN getDN(Entry e) { return e != null ? e.getDN() : DN.nullDN(); }
/** * Tests performing an internal search using the VLV control to retrieve a subset of the entries * using an assertion value before any actual value in the list. * * @throws Exception If an unexpected problem occurred. */ @Test() public void testInternalSearchByValueBeforeAll() throws Exception { populateDB(); InternalClientConnection conn = InternalClientConnection.getRootConnection(); ArrayList<Control> requestControls = new ArrayList<Control>(); requestControls.add(new ServerSideSortRequestControl("givenName")); requestControls.add(new VLVRequestControl(0, 3, ByteString.valueOf("a"))); InternalSearchOperation internalSearch = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), requestControls, DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, SearchFilter.createFilterFromString("(objectClass=person)"), null, null); internalSearch.run(); assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); expectedDNOrder.add(aaccfJohnsonDN); // Aaccf expectedDNOrder.add(aaronZimmermanDN); // Aaron expectedDNOrder.add(albertZimmermanDN); // Albert, lower entry ID expectedDNOrder.add(albertSmithDN); // Albert, higher entry ID ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); for (Entry e : internalSearch.getSearchEntries()) { returnedDNOrder.add(e.getDN()); } assertEquals(returnedDNOrder, expectedDNOrder); List<Control> responseControls = internalSearch.getResponseControls(); assertNotNull(responseControls); assertEquals(responseControls.size(), 2); ServerSideSortResponseControl sortResponse = null; VLVResponseControl vlvResponse = null; for (Control c : responseControls) { if (c.getOID().equals(OID_SERVER_SIDE_SORT_RESPONSE_CONTROL)) { if (c instanceof LDAPControl) { sortResponse = ServerSideSortResponseControl.DECODER.decode( c.isCritical(), ((LDAPControl) c).getValue()); } else { sortResponse = (ServerSideSortResponseControl) c; } } else if (c.getOID().equals(OID_VLV_RESPONSE_CONTROL)) { if (c instanceof LDAPControl) { vlvResponse = VLVResponseControl.DECODER.decode(c.isCritical(), ((LDAPControl) c).getValue()); } else { vlvResponse = (VLVResponseControl) c; } } else { fail("Response control with unexpected OID " + c.getOID()); } } assertNotNull(sortResponse); assertEquals(sortResponse.getResultCode(), 0); assertNotNull(vlvResponse); assertEquals(vlvResponse.getVLVResultCode(), 0); assertEquals(vlvResponse.getTargetPosition(), 1); assertEquals(vlvResponse.getContentCount(), 9); }
/** * Tests performing an internal search using the server-side sort control to sort the entries in * order of ascending givenName and descending sn values. * * @throws Exception If an unexpected problem occurred. */ @Test() public void testInternalSearchGivenNameAscendingSnDescending() throws Exception { populateDB(); InternalClientConnection conn = InternalClientConnection.getRootConnection(); ArrayList<Control> requestControls = new ArrayList<Control>(); requestControls.add(new ServerSideSortRequestControl("givenName,-sn")); InternalSearchOperation internalSearch = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), requestControls, DN.decode("dc=example,dc=com"), SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, SearchFilter.createFilterFromString("(objectClass=person)"), null, null); internalSearch.run(); assertEquals(internalSearch.getResultCode(), ResultCode.SUCCESS); ArrayList<DN> expectedDNOrder = new ArrayList<DN>(); expectedDNOrder.add(aaccfJohnsonDN); // Aaccf expectedDNOrder.add(aaronZimmermanDN); // Aaron expectedDNOrder.add(albertZimmermanDN); // Albert, higher sn expectedDNOrder.add(albertSmithDN); // Albert, lower sn expectedDNOrder.add(lowercaseMcGeeDN); // lowercase expectedDNOrder.add(margaretJonesDN); // Maggie expectedDNOrder.add(maryJonesDN); // Mary expectedDNOrder.add(samZweckDN); // Sam expectedDNOrder.add(zorroDN); // No first name ArrayList<DN> returnedDNOrder = new ArrayList<DN>(); for (Entry e : internalSearch.getSearchEntries()) { returnedDNOrder.add(e.getDN()); } assertEquals(returnedDNOrder, expectedDNOrder); List<Control> responseControls = internalSearch.getResponseControls(); assertNotNull(responseControls); assertEquals(responseControls.size(), 1); ServerSideSortResponseControl responseControl; Control c = responseControls.get(0); if (c instanceof ServerSideSortResponseControl) { responseControl = (ServerSideSortResponseControl) c; } else { responseControl = ServerSideSortResponseControl.DECODER.decode( c.isCritical(), ((LDAPControl) c).getValue()); } assertEquals(responseControl.getResultCode(), 0); assertNull(responseControl.getAttributeType()); responseControl.toString(); }
/** {@inheritDoc} */ @Override public void addEntry(Entry entry, AddOperation addOperation) throws DirectoryException { throw new DirectoryException( ResultCode.UNWILLING_TO_PERFORM, ERR_BACKEND_ADD_NOT_SUPPORTED.get(String.valueOf(entry.getDN()), getBackendID())); }