| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.server.core.authn.ppolicy; |
| |
| |
| import static org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.INSUFFICIENT_PASSWORD_QUALITY; |
| import static org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.PASSWORD_EXPIRED; |
| import static org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.PASSWORD_IN_HISTORY; |
| import static org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.PASSWORD_TOO_SHORT; |
| import static org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyErrorEnum.PASSWORD_TOO_YOUNG; |
| import static org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants.*; |
| import static org.apache.directory.server.core.integ.IntegrationUtils.getAdminNetworkConnection; |
| import static org.apache.directory.server.core.integ.IntegrationUtils.getNetworkConnectionAs; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNotSame; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.apache.directory.api.ldap.codec.api.LdapApiService; |
| import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory; |
| import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicy; |
| import org.apache.directory.api.ldap.extras.controls.ppolicy.PasswordPolicyImpl; |
| import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator; |
| import org.apache.directory.api.ldap.model.constants.LdapSecurityConstants; |
| import org.apache.directory.api.ldap.model.constants.PasswordPolicySchemaConstants; |
| import org.apache.directory.api.ldap.model.constants.SchemaConstants; |
| import org.apache.directory.api.ldap.model.entry.Attribute; |
| import org.apache.directory.api.ldap.model.entry.DefaultEntry; |
| import org.apache.directory.api.ldap.model.entry.Entry; |
| import org.apache.directory.api.ldap.model.exception.LdapException; |
| import org.apache.directory.api.ldap.model.message.AddRequest; |
| import org.apache.directory.api.ldap.model.message.AddRequestImpl; |
| import org.apache.directory.api.ldap.model.message.AddResponse; |
| import org.apache.directory.api.ldap.model.message.BindRequest; |
| import org.apache.directory.api.ldap.model.message.BindRequestImpl; |
| import org.apache.directory.api.ldap.model.message.BindResponse; |
| import org.apache.directory.api.ldap.model.message.Control; |
| import org.apache.directory.api.ldap.model.message.ModifyRequest; |
| import org.apache.directory.api.ldap.model.message.ModifyRequestImpl; |
| import org.apache.directory.api.ldap.model.message.ModifyResponse; |
| import org.apache.directory.api.ldap.model.message.Response; |
| import org.apache.directory.api.ldap.model.message.ResultCodeEnum; |
| import org.apache.directory.api.ldap.model.name.Dn; |
| import org.apache.directory.api.ldap.model.password.PasswordUtil; |
| import org.apache.directory.ldap.client.api.LdapConnection; |
| import org.apache.directory.ldap.client.api.LdapNetworkConnection; |
| import org.apache.directory.server.annotations.CreateLdapServer; |
| import org.apache.directory.server.annotations.CreateTransport; |
| import org.apache.directory.server.core.annotations.CreateDS; |
| import org.apache.directory.server.core.api.InterceptorEnum; |
| import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration; |
| import org.apache.directory.server.core.authn.AuthenticationInterceptor; |
| import org.apache.directory.server.core.integ.AbstractLdapTestUnit; |
| import org.apache.directory.server.core.integ.FrameworkRunner; |
| import org.apache.directory.server.core.integ.IntegrationUtils; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| |
| /** |
| * Test cases for testing PasswordPolicy implementation. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| @RunWith(FrameworkRunner.class) |
| @CreateLdapServer(transports = |
| { |
| @CreateTransport(protocol = "LDAP"), |
| @CreateTransport(protocol = "LDAPS") }) |
| // disable changelog, for more info see DIRSERVER-1528 |
| @CreateDS(enableChangeLog = false, name = "PasswordPolicyTest") |
| public class PasswordPolicyIT extends AbstractLdapTestUnit |
| { |
| private PasswordPolicyConfiguration policyConfig; |
| |
| private static final LdapApiService codec = LdapApiServiceFactory.getSingleton(); |
| |
| private static final PasswordPolicyDecorator PP_REQ_CTRL = |
| new PasswordPolicyDecorator( codec, new PasswordPolicyImpl() ); |
| |
| |
| @Before |
| public void setPwdPolicy() throws LdapException |
| { |
| policyConfig = new PasswordPolicyConfiguration(); |
| |
| policyConfig.setPwdMaxAge( 110 ); |
| policyConfig.setPwdFailureCountInterval( 30 ); |
| policyConfig.setPwdMaxFailure( 2 ); |
| policyConfig.setPwdLockout( true ); |
| policyConfig.setPwdLockoutDuration( 0 ); |
| policyConfig.setPwdMinLength( 5 ); |
| policyConfig.setPwdInHistory( 5 ); |
| policyConfig.setPwdExpireWarning( 600 ); |
| policyConfig.setPwdGraceAuthNLimit( 5 ); |
| policyConfig.setPwdCheckQuality( 2 ); // DO NOT allow the password if its quality can't be checked |
| |
| PpolicyConfigContainer policyContainer = new PpolicyConfigContainer(); |
| policyContainer.setDefaultPolicy( policyConfig ); |
| AuthenticationInterceptor authenticationInterceptor = (AuthenticationInterceptor)getService().getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR.getName() ); |
| authenticationInterceptor.setPwdPolicies( policyContainer ); |
| |
| AuthenticationInterceptor authInterceptor = ( AuthenticationInterceptor ) getService() |
| .getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR.getName() ); |
| |
| authInterceptor.loadPwdPolicyStateAtributeTypes(); |
| } |
| |
| |
| @After |
| public void closeConnections() |
| { |
| IntegrationUtils.closeConnections(); |
| } |
| |
| |
| @Test |
| public void testAddUserWithClearTextPwd() throws Exception |
| { |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=user,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: user", |
| "sn: user_sn", |
| "userPassword: 1234" ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, addResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNotNull( respCtrl ); |
| assertEquals( PASSWORD_TOO_SHORT, respCtrl.getResponse().getPasswordPolicyError() ); |
| |
| Attribute pwdAt = userEntry.get( SchemaConstants.USER_PASSWORD_AT ); |
| pwdAt.clear(); |
| pwdAt.add( "12345" ); |
| |
| addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| LdapConnection userConnection = getNetworkConnectionAs( getLdapServer(), userDn.getName(), "12345" ); |
| assertNotNull( userConnection ); |
| assertTrue( userConnection.isAuthenticated() ); |
| } |
| |
| |
| @Test |
| public void testAddUserWithHashedPwd() throws Exception |
| { |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| byte[] password = PasswordUtil.createStoragePassword( "12345", LdapSecurityConstants.HASH_METHOD_CRYPT ); |
| |
| Entry userEntry = new DefaultEntry( "cn=hashedpwd,ou=system" ); |
| userEntry.add( SchemaConstants.OBJECT_CLASS, SchemaConstants.PERSON_OC ); |
| userEntry.add( SchemaConstants.CN_AT, "hashedpwd" ); |
| userEntry.add( SchemaConstants.SN_AT, "hashedpwd_sn" ); |
| userEntry.add( SchemaConstants.USER_PASSWORD_AT, password ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, addResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNotNull( respCtrl ); |
| assertEquals( INSUFFICIENT_PASSWORD_QUALITY, respCtrl.getResponse().getPasswordPolicyError() ); |
| |
| policyConfig.setPwdCheckQuality( 1 ); // allow the password if its quality can't be checked |
| Attribute pwdAt = userEntry.get( SchemaConstants.USER_PASSWORD_AT ); |
| pwdAt.clear(); |
| pwdAt.add( password ); |
| |
| addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| LdapConnection userConnection = getNetworkConnectionAs( getLdapServer(), "cn=hashedpwd,ou=system", "12345" ); |
| assertNotNull( userConnection ); |
| assertTrue( userConnection.isAuthenticated() ); |
| } |
| |
| |
| @Test |
| public void testPwdLockoutForever() throws Exception |
| { |
| policyConfig.setPwdMaxFailure( 2 ); |
| policyConfig.setPwdLockout( true ); |
| policyConfig.setPwdLockoutDuration( 0 ); |
| policyConfig.setPwdGraceAuthNLimit( 2 ); |
| policyConfig.setPwdFailureCountInterval( 30 ); |
| |
| LdapConnection adminConnection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=user2,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: user2", |
| "sn: user_sn", |
| "userPassword: 12345" ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = adminConnection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| BindRequest bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( "1234" ); // wrong password |
| bindReq.addControl( PP_REQ_CTRL ); |
| |
| LdapConnection userConnection = new LdapNetworkConnection( "localhost", ldapServer.getPort() ); |
| |
| for( int i=0; i< 3; i++ ) |
| { |
| userConnection.bind( bindReq ); |
| assertFalse( userConnection.isAuthenticated() ); |
| } |
| |
| // Added an extra wait (for Windows) |
| Thread.sleep( 2000 ); |
| |
| userEntry = adminConnection.lookup( userDn, SchemaConstants.ALL_ATTRIBUTES_ARRAY ); |
| Attribute pwdAccountLockedTime = userEntry.get( PasswordPolicySchemaConstants.PWD_ACCOUNT_LOCKED_TIME_AT ); |
| assertNotNull( pwdAccountLockedTime ); |
| assertEquals( "000001010000Z", pwdAccountLockedTime.getString() ); |
| |
| bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( "12345" ); // correct password |
| bindReq.addControl( PP_REQ_CTRL ); |
| userConnection.bind( bindReq ); |
| assertFalse( userConnection.isAuthenticated() ); // but still fails cause account is locked |
| |
| userConnection.close(); |
| |
| // test deleting the password, it should clear all the ppolicy related attributes except the ppolicy subentry |
| |
| ModifyRequest modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| modReq.addControl( PP_REQ_CTRL ); |
| modReq.remove( userEntry.get( SchemaConstants.USER_PASSWORD_AT ) ); |
| |
| ModifyResponse modResp = adminConnection.modify( modReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, modResp.getLdapResult().getResultCode() ); |
| |
| userEntry = adminConnection.lookup( userDn, "+" ); |
| assertNull( userEntry.get( PWD_FAILURE_TIME_AT ) ); |
| assertNull( userEntry.get( PWD_GRACE_USE_TIME_AT ) ); |
| assertNull( userEntry.get( PWD_HISTORY_AT ) ); |
| assertNull( userEntry.get( PWD_CHANGED_TIME_AT ) ); |
| assertNull( userEntry.get( PWD_ACCOUNT_LOCKED_TIME_AT ) ); |
| } |
| |
| |
| @Test |
| public void testPwdMinAge() throws Exception |
| { |
| policyConfig.setPwdMinAge( 5 ); |
| |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userMinAge,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userMinAge", |
| "sn: userMinAge_sn", |
| "userPassword: 12345"); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| ModifyRequest modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| modReq.addControl( PP_REQ_CTRL ); |
| modReq.replace( SchemaConstants.USER_PASSWORD_AT, "123456" ); |
| |
| ModifyResponse modResp = connection.modify( modReq ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, modResp.getLdapResult().getResultCode() ); |
| |
| respCtrl = getPwdRespCtrl( modResp ); |
| assertEquals( PASSWORD_TOO_YOUNG, respCtrl.getResponse().getPasswordPolicyError() ); |
| |
| Thread.sleep( 5000 ); |
| |
| modResp = connection.modify( modReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, modResp.getLdapResult().getResultCode() ); |
| |
| LdapConnection userConnection = getNetworkConnectionAs( getLdapServer(), userDn.getName(), "123456" ); |
| assertNotNull( userConnection ); |
| assertTrue( userConnection.isAuthenticated() ); |
| } |
| |
| |
| @Test |
| public void testPwdHistory() throws Exception |
| { |
| policyConfig.setPwdInHistory( 2 ); |
| |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userPwdHist,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userPwdHist", |
| "sn: userPwdHist_sn", |
| "userPassword: 12345" ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| connection.add( addRequest ); |
| |
| Entry entry = connection.lookup( userDn, "*", "+" ); |
| |
| Attribute pwdHistAt = entry.get( PasswordPolicySchemaConstants.PWD_HISTORY_AT ); |
| assertNotNull( pwdHistAt ); |
| assertEquals( 1, pwdHistAt.size() ); |
| |
| Thread.sleep( 1000 );// to avoid creating a history value with the same timestamp |
| ModifyRequest modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| modReq.addControl( PP_REQ_CTRL ); |
| modReq.replace( SchemaConstants.USER_PASSWORD_AT, "67891" ); |
| |
| connection.modify( modReq ); |
| |
| entry = connection.lookup( userDn, "*", "+" ); |
| |
| pwdHistAt = entry.get( PasswordPolicySchemaConstants.PWD_HISTORY_AT ); |
| assertNotNull( pwdHistAt ); |
| assertEquals( 2, pwdHistAt.size() ); |
| |
| Thread.sleep( 1000 );// to avoid creating a history value with the same timestamp |
| modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| modReq.addControl( PP_REQ_CTRL ); |
| modReq.replace( SchemaConstants.USER_PASSWORD_AT, "abcde" ); |
| |
| ModifyResponse modResp = connection.modify( modReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, modResp.getLdapResult().getResultCode() ); |
| |
| entry = connection.lookup( userDn, "*", "+" ); |
| pwdHistAt = entry.get( PasswordPolicySchemaConstants.PWD_HISTORY_AT ); |
| assertNotNull( pwdHistAt ); |
| |
| // it should still hold only 2 values |
| assertEquals( 2, pwdHistAt.size() ); |
| |
| // try to reuse the password, should fail |
| modResp = connection.modify( modReq ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, modResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( modResp ); |
| assertEquals( PASSWORD_IN_HISTORY, respCtrl.getResponse().getPasswordPolicyError() ); |
| } |
| |
| |
| @Test |
| public void testPwdLength() throws Exception |
| { |
| policyConfig.setPwdMinLength( 5 ); |
| policyConfig.setPwdMaxLength( 7 ); |
| policyConfig.setPwdCheckQuality( 2 ); |
| |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userLen,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userLen", |
| "sn: userLen_sn", |
| "userPassword: 1234"); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, addResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNotNull( respCtrl ); |
| assertEquals( PASSWORD_TOO_SHORT, respCtrl.getResponse().getPasswordPolicyError() ); |
| |
| Attribute pwdAt = userEntry.get( SchemaConstants.USER_PASSWORD_AT ); |
| pwdAt.clear(); |
| pwdAt.add( "12345678" ); |
| |
| addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.CONSTRAINT_VIOLATION, addResp.getLdapResult().getResultCode() ); |
| |
| respCtrl = getPwdRespCtrl( addResp ); |
| assertNotNull( respCtrl ); |
| assertEquals( INSUFFICIENT_PASSWORD_QUALITY, respCtrl.getResponse().getPasswordPolicyError() ); |
| |
| pwdAt = userEntry.get( SchemaConstants.USER_PASSWORD_AT ); |
| pwdAt.clear(); |
| pwdAt.add( "123456" ); |
| |
| addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| } |
| |
| |
| @Test |
| public void testPwdMaxAgeAndGraceAuth() throws Exception |
| { |
| policyConfig.setPwdMaxAge( 5 ); |
| policyConfig.setPwdExpireWarning( 4 ); |
| policyConfig.setPwdGraceAuthNLimit( 2 ); |
| |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userMaxAge,ou=system" ); |
| String password = "12345"; |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userMaxAge", |
| "sn: userMaxAge_sn", |
| "userPassword: " + password ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| connection.add( addRequest ); |
| |
| BindRequest bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( password.getBytes() ); |
| bindReq.addControl( PP_REQ_CTRL ); |
| |
| LdapConnection userCon= new LdapNetworkConnection( "localhost", ldapServer.getPort() ); |
| userCon.setTimeOut(0); |
| |
| Thread.sleep( 1000 ); // sleep for one second so that the password expire warning will be sent |
| |
| BindResponse bindResp = userCon.bind( bindReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, bindResp.getLdapResult().getResultCode() ); |
| |
| PasswordPolicy respCtrl = getPwdRespCtrl( bindResp ); |
| assertNotNull( respCtrl ); |
| assertTrue( respCtrl.getResponse().getTimeBeforeExpiration() > 0 ); |
| |
| Thread.sleep( 4000 ); // sleep for four seconds so that the password expires |
| |
| // bind for two more times, should succeed |
| bindResp = userCon.bind( bindReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, bindResp.getLdapResult().getResultCode() ); |
| respCtrl = getPwdRespCtrl( bindResp ); |
| assertNotNull( respCtrl ); |
| assertEquals( 1, respCtrl.getResponse().getGraceAuthNsRemaining() ); |
| |
| // this extra second sleep is necessary to modify pwdGraceUseTime attribute with a different timestamp |
| Thread.sleep( 1000 ); |
| bindResp = userCon.bind( bindReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, bindResp.getLdapResult().getResultCode() ); |
| respCtrl = getPwdRespCtrl( bindResp ); |
| assertEquals( 0, respCtrl.getResponse().getGraceAuthNsRemaining() ); |
| |
| // this time it should fail |
| bindResp = userCon.bind( bindReq ); |
| assertEquals( ResultCodeEnum.INVALID_CREDENTIALS, bindResp.getLdapResult().getResultCode() ); |
| |
| respCtrl = getPwdRespCtrl( bindResp ); |
| assertEquals( PASSWORD_EXPIRED, respCtrl.getResponse().getPasswordPolicyError() ); |
| } |
| |
| |
| @Test |
| public void testModifyPwdSubentry() throws Exception |
| { |
| LdapConnection connection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=ppolicySubentry,ou=system" ); |
| String password = "12345"; |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: ppolicySubentry", |
| "sn: ppolicySubentry_sn", |
| "userPassword: " + password, |
| "pwdPolicySubEntry:" + userDn.getName() ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = connection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| |
| userEntry = connection.lookup( userDn, "*", "+" ); |
| assertEquals( userDn.getName(), userEntry.get( "pwdPolicySubEntry" ).getString() ); |
| |
| ModifyRequest modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| String modSubEntryDn = "cn=policy,ou=system"; |
| modReq.replace( "pwdPolicySubEntry", modSubEntryDn ); |
| ModifyResponse modResp = connection.modify( modReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, modResp.getLdapResult().getResultCode() ); |
| |
| userEntry = connection.lookup( userDn, "*", "+" ); |
| assertEquals( modSubEntryDn, userEntry.get( "pwdPolicySubEntry" ).getString() ); |
| |
| // try to modify the subentry as a non-admin |
| connection = new LdapNetworkConnection( "localhost", getLdapServer().getPort() ); |
| connection.bind( userDn.getName(), password ); |
| |
| modResp = connection.modify( modReq ); |
| modReq.replace( "pwdPolicySubEntry", userDn.getName() ); |
| assertEquals( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, modResp.getLdapResult().getResultCode() ); |
| } |
| |
| |
| @Test |
| public void testGraceAuth() throws Exception |
| { |
| policyConfig.setPwdMaxFailure( 2 ); |
| policyConfig.setPwdLockout( true ); |
| policyConfig.setPwdLockoutDuration( 0 ); |
| policyConfig.setPwdGraceAuthNLimit( 2 ); |
| policyConfig.setPwdFailureCountInterval( 60 ); |
| policyConfig.setPwdMaxAge( 1 ); |
| |
| LdapConnection adminConnection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userGrace,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userGrace", |
| "sn: userGrace_sn", |
| "userPassword: 12345" ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = adminConnection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| BindRequest bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( "12345" ); // grace login |
| bindReq.addControl( PP_REQ_CTRL ); |
| |
| LdapConnection userConnection = new LdapNetworkConnection( "localhost", ldapServer.getPort() ); |
| |
| Thread.sleep( 2000 ); // let the password expire |
| BindResponse bindResp = userConnection.bind( bindReq ); |
| assertTrue( userConnection.isAuthenticated() ); |
| PasswordPolicy ppolicy = getPwdRespCtrl( bindResp ); |
| assertEquals( 1, ppolicy.getResponse().getGraceAuthNsRemaining() ); |
| |
| userEntry = adminConnection.lookup( userDn, "+" ); |
| Attribute pwdGraceAuthUseTime = userEntry.get( PasswordPolicySchemaConstants.PWD_GRACE_USE_TIME_AT ); |
| assertNotNull( pwdGraceAuthUseTime ); |
| |
| Attribute pwdChangedTime = userEntry.get( PasswordPolicySchemaConstants.PWD_CHANGED_TIME_AT ); |
| |
| ModifyRequest modReq = new ModifyRequestImpl(); |
| modReq.setName( userDn ); |
| modReq.replace( SchemaConstants.USER_PASSWORD_AT, "secret1" ); |
| ModifyResponse modResp = userConnection.modify( modReq ); |
| assertEquals( ResultCodeEnum.SUCCESS, modResp.getLdapResult().getResultCode() ); |
| |
| userEntry = adminConnection.lookup( userDn, "+" ); |
| pwdGraceAuthUseTime = userEntry.get( PasswordPolicySchemaConstants.PWD_GRACE_USE_TIME_AT ); |
| assertNull( pwdGraceAuthUseTime ); |
| |
| Attribute latestPwdChangedTime = userEntry.get( PasswordPolicySchemaConstants.PWD_CHANGED_TIME_AT ); |
| assertNotSame( pwdChangedTime.getString(), latestPwdChangedTime.getString() ); |
| |
| userConnection.close(); |
| } |
| |
| |
| @Test |
| public void testPwdLockoutWithDuration() throws Exception |
| { |
| policyConfig.setPwdMaxFailure( 2 ); |
| policyConfig.setPwdLockout( true ); |
| policyConfig.setPwdLockoutDuration( 5 ); //5 sec |
| policyConfig.setPwdGraceAuthNLimit( 2 ); |
| policyConfig.setPwdFailureCountInterval( 0 ); |
| |
| LdapConnection adminConnection = getAdminNetworkConnection( getLdapServer() ); |
| |
| Dn userDn = new Dn( "cn=userLockout,ou=system" ); |
| Entry userEntry = new DefaultEntry( |
| userDn.toString(), |
| "ObjectClass: top", |
| "ObjectClass: person", |
| "cn: userLockout", |
| "sn: userLockout_sn", |
| "userPassword: 12345" ); |
| |
| AddRequest addRequest = new AddRequestImpl(); |
| addRequest.setEntry( userEntry ); |
| addRequest.addControl( PP_REQ_CTRL ); |
| |
| AddResponse addResp = adminConnection.add( addRequest ); |
| assertEquals( ResultCodeEnum.SUCCESS, addResp.getLdapResult().getResultCode() ); |
| PasswordPolicy respCtrl = getPwdRespCtrl( addResp ); |
| assertNull( respCtrl ); |
| |
| BindRequest bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( "1234" ); // wrong password |
| bindReq.addControl( PP_REQ_CTRL ); |
| |
| LdapConnection userConnection = new LdapNetworkConnection( "localhost", ldapServer.getPort() ); |
| |
| for( int i=0; i< 4; i++ ) |
| { |
| userConnection.bind( bindReq ); |
| assertFalse( userConnection.isAuthenticated() ); |
| } |
| |
| userEntry = adminConnection.lookup( userDn, "+" ); |
| Attribute pwdAccountLockedTime = userEntry.get( PasswordPolicySchemaConstants.PWD_ACCOUNT_LOCKED_TIME_AT ); |
| assertNotNull( pwdAccountLockedTime ); |
| |
| Thread.sleep( 10000 ); |
| bindReq = new BindRequestImpl(); |
| bindReq.setDn( userDn ); |
| bindReq.setCredentials( "12345" ); // correct password |
| bindReq.addControl( PP_REQ_CTRL ); |
| userConnection.setTimeOut( Long.MAX_VALUE ); |
| userConnection.bind( bindReq ); |
| assertTrue( userConnection.isAuthenticated() ); |
| |
| userConnection.close(); |
| } |
| |
| |
| private PasswordPolicy getPwdRespCtrl( Response resp ) throws Exception |
| { |
| Control control = resp.getControls().get( PP_REQ_CTRL.getOid() ); |
| |
| if ( control == null ) |
| { |
| return null; |
| } |
| |
| return ((PasswordPolicyDecorator)control).getDecorated(); |
| } |
| } |