Announcement Announcement Module
Collapse
No announcement yet.
Authentication Failing after password change Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Authentication Failing after password change

    Spring ldap 1.3

    step A. createa user in AD like this:

    Attributes personAttributes = new BasicAttributes();

    personAttributes.put( "objectclass", "person" );
    personAttributes.put( "objectclass", "user" );
    personAttributes.put( "givenName", luzer.getFirstName() );
    personAttributes.put( "userPrincipalName", luzer.getEmailAddress() );
    personAttributes.put( "sn", luzer.getLastName());
    personAttributes.put( "description", "Created via WFM 5.0 Flex app" );
    personAttributes.put( "sAMAccountName", luzer.getFirstName().toUpperCase()+ "." + luzer.getLastName().toUpperCase() );
    personAttributes.put( "userAccountControl", "512" ); /// 512 = normal luser
    personAttributes.put( "pwdLastSet", "0" ); /// force user to change password on next login......


    // PASSWORD stuff.....
    personAttributes.put("unicodepwd", encodePassword( luzer.getPassword() ) );

    // Set up user distinguished name and clreate it.
    DistinguishedName newUserDN = userToDistinguishedName( luzer );
    ldapTemplate.bind(newUserDN, null, personAttributes);


    All goes well....
    User tries to authenticate first time we get back ".... AcceptSecurityContext error, data 773 ....." which means:
    // 52e - invalid credentials
    // 530 - not permitted to logon at this time
    // 532 - password expired
    // 533 - account disabled
    // 701 - account expired
    // 773 - user must reset password

    So user is forced to change password. and we do i like this:

    ModificationItem repitem = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodepwd", encodePassword( luzer.getPassword() )) );
    DistinguishedName userDN = userToDistinguishedName( luzer );
    ldapTemplate.modifyAttributes( userDN, new ModificationItem[] { repitem } );

    all goes well.....
    but now user can not log in anymore......

    org.springframework.security.AuthenticationService Exception: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001BD, problem 2001 (NO_OBJECT), data 0, best match of:
    'OU=TRX DEV,OU=WFM LDAP,OU=External Clients,DC=trxfs,DC=trx,DC=com'

    so what the heck is going on?
    ldap base is pointing to
    OU=TRX DEV,OU=WFM LDAP,OU=External Clients,DC=trxfs,DC=trx,DC=com

    so we create and modify users right at the "root"....
    I have spent all day on this and all permutations produce same results.
    reseting password with remove+add attribute produces same results....

  • #2
    Could you please provide your configuration, the userToDistinguishedName code, and the code you're using for authentication? That would greatly simplify tracking down this problem.

    Comment


    • #3
      CODE for modifying managingin AD

      public void createUser(User luzer) throws DuplicateUserException, PasswordStrengthException, LdapSaveException {
      try {
      Attributes personAttributes = new BasicAttributes();

      personAttributes.put( "objectclass", "person" );
      personAttributes.put( "objectclass", "user" );
      personAttributes.put( "givenName", luzer.getFirstName() );
      personAttributes.put( "userPrincipalName", luzer.getEmailAddress() );
      personAttributes.put( "sn", luzer.getLastName());
      personAttributes.put( "description", "Created via WFM 5.0 Flex app" );
      personAttributes.put( "sAMAccountName", luzer.getFirstName().toUpperCase()+ "." + luzer.getLastName().toUpperCase() );
      personAttributes.put( "userAccountControl", "512" ); /// 512 = normal luser
      personAttributes.put( "pwdLastSet", "0" ); /// force user to change password on next login......

      // PASSWORD stuff.....
      personAttributes.put("unicodepwd", encodePassword( luzer.getPassword() ) );

      // Set up user distinguished name and clreate it.
      DistinguishedName newUserDN = userToDistinguishedName( luzer );
      ldapTemplate.bind(newUserDN, null, personAttributes);

      } catch ( InvalidAttributeValueException exc ) {
      logger.error( "createUser()", exc);
      throw new LdapSaveException( exc.getMessage() );
      } catch ( NameAlreadyBoundException exc ) { /// USER EXISTS....
      logger.error( "createUser()", exc);
      throw new DuplicateUserException( "User ["+ luzer.getEmailAddress() + "] allready exists in AD." );
      } catch ( NameNotFoundException exc ) {
      logger.error( "createUser()", exc);
      throw new LdapSaveException( exc.getMessage() );
      } catch ( OperationNotSupportedException exc ) { // CAN NOT ADD USER
      logger.error( "createUser()", exc);
      throw new PasswordStrengthException( exc.getMessage() );
      } catch ( Exception exc ) {
      logger.error( "createUser()", exc);
      throw new LdapSaveException( exc.getMessage() );
      }
      }

      public void changePassword( User luzer ) throws PasswordStrengthException {
      try {
      ModificationItem repitem = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodepwd", encodePassword( luzer.getPassword() )) );
      DistinguishedName userDN = userToDistinguishedName( luzer );
      ldapTemplate.modifyAttributes( userDN, new ModificationItem[] { repitem } );
      } catch ( Exception exc ) {
      logger.error( "changePassword()", exc);
      throw new PasswordStrengthException( exc.getMessage() );
      }
      }


      private byte[] encodePassword(String password) throws UnsupportedEncodingException {
      String newQuotedPassword = "\"" + password + "\"";
      return newQuotedPassword.getBytes("UTF-16LE");
      }

      private DistinguishedName userToDistinguishedName( User luzer ) {
      return new DistinguishedName( "cn=user_"+luzer.getUserId() ); // cn=user_12345
      }

      Comment


      • #4
        Authentication code

        public class ADBindAuthenticator extends AbstractLdapAuthenticator {

        protected static final Logger logger = Logger.getLogger( ADBindAuthenticator.class );

        public ADBindAuthenticator(SpringSecurityContextSource contextSource) {
        super(contextSource);
        }

        public DirContextOperations authenticate(Authentication authentication) {
        DirContextOperations user = null;
        Assert.isInstanceOf(UsernamePasswordAuthentication Token.class, authentication, "Can only process UsernamePasswordAuthenticationToken objects");

        String username = authentication.getName();
        String password = (String)authentication.getCredentials();

        // If DN patterns are configured, try authenticating with them directly
        Iterator<?> dns = getUserDns(username).iterator();

        while (dns.hasNext() && user == null) {
        user = bindWithDn((String) dns.next(), username, password);
        }

        // Otherwise use the configured locator to find the user
        // and authenticate with the returned DN.
        if (user == null && getUserSearch() != null) {
        DirContextOperations userFromSearch = getUserSearch().searchForUser(username);
        user = bindWithDn(userFromSearch.getDn().toString(), username, password);
        }

        if (user == null) {
        throw new BadCredentialsException(messages.getMessage("BindA uthenticator.badCredentials", "Bad credentials"));
        }

        return user;
        }

        private DirContextOperations bindWithDn(String userDn, String username, String password) {

        SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate( new BindWithSpecificDnContextSource((SpringSecurityCon textSource) getContextSource(), userDn, password));

        try {
        return template.retrieveEntry(userDn, getUserAttributes());

        } catch (BadCredentialsException e) {
        // 52e - invalid credentials
        // 530 - not permitted to logon at this time
        // 532 - password expired
        // 533 - account disabled
        // 701 - account expired
        // 773 - user must reset password
        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 773" ) >= 0 )
        throw new BadCredentialsException("MUST_CHANGE_PASSWORD");

        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 532" ) >= 0 )
        throw new BadCredentialsException("PASSWORD_EXPIRED");

        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 533" ) >= 0 )
        throw new BadCredentialsException("ACCOUNT_DISABLED");

        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 701" ) >= 0 )
        throw new BadCredentialsException("ACCOUNT_EXPIRED");

        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 530" ) >= 0 )
        throw new BadCredentialsException("NOT_ALLOWED_LOGON");

        if( e.getMessage().indexOf( "AcceptSecurityContext error, data 52e" ) >= 0 )
        throw new BadCredentialsException("INVALID_CREDENTIALS");

        }
        return null;
        }

        private class BindWithSpecificDnContextSource implements ContextSource {
        private SpringSecurityContextSource ctxFactory;
        DistinguishedName userDn;
        private String password;

        public BindWithSpecificDnContextSource(SpringSecurityCont extSource ctxFactory, String userDn, String password) {
        this.ctxFactory = ctxFactory;
        this.userDn = new DistinguishedName(userDn);
        this.userDn.prepend(ctxFactory.getBaseLdapPath());
        this.password = password;
        }

        public DirContext getReadOnlyContext() throws DataAccessException {
        return ctxFactory.getReadWriteContext(userDn.toString(), password);
        }

        public DirContext getReadWriteContext() throws DataAccessException {
        return getReadOnlyContext();
        }

        public DirContext getContext(String principal, String credentials) throws NamingException {
        return getReadOnlyContext();
        }
        }

        }

        Comment


        • #5
          Config

          <bean id="password-reset-service" class="com.trx.wfm.svc.PasswordResetService" parent="base-service">
          <property name="ldapUserDAO" ref="ldapUserDAO" />
          <property name="ldapProvider" ref="ldapProvider" />
          <property name="userDao" ref="user-dao"/>
          </bean>

          <bean id="ldapUserSearch" class="org.springframework.security.ldap.search.Fi lterBasedLdapUserSearch">
          <constructor-arg index="0" value="${ldap.user.base}" />
          <constructor-arg index="1" value="(&amp;(userPrincipalName={0}))" />
          <constructor-arg index="2" ref="initialDirContextFactory" />
          </bean>

          <bean id="authenticator" class="com.trx.wfm.security.ADBindAuthenticator">
          <constructor-arg ref="initialDirContextFactory" />
          <property name="userSearch" ref="ldapUserSearch" />
          </bean>

          <bean id="populator" class="org.springframework.security.ldap.populator .DefaultLdapAuthoritiesPopulator">
          <constructor-arg ref="initialDirContextFactory" />
          <constructor-arg value="ou=Corp" />
          <property name="groupRoleAttribute" value="ou" />
          </bean>

          <bean id="initialDirContextFactory" class="org.springframework.security.ldap.DefaultSp ringSecurityContextSource">
          <constructor-arg value="${ldap.url}" />
          <property name="base" value="${ldap.base}" />
          <property name="userDn" value="${ldap.admin.bind.userdn}" />
          <property name="password" value="${ldap.admin.bind.password}" />
          </bean>

          <bean id="ldapProvider" class="org.springframework.security.providers.ldap .LdapAuthenticationProvider">
          <constructor-arg ref="authenticator" />
          <constructor-arg ref="populator" />
          </bean>

          <bean id="ldapAuthenticationProvider" class="com.trx.wfm.security.LdapWfmAuthenticationP rovider">
          <property name="ldapProvider" ref="ldapProvider" />
          <property name="userdao" ref="user-dao" />
          </bean>

          <bean id="ldapContextSource" class="org.springframework.ldap.core.support.LdapC ontextSource">
          <property name="url" value="${ldap.url}" />
          <property name="base" value="${ldap.base}" />
          <property name="userDn" value="${ldap.admin.bind.userdn}" />
          <property name="password" value="${ldap.admin.bind.password}" />
          </bean>

          <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate" >
          <property name="contextSource" ref="ldapContextSource" />
          </bean>

          <bean id="ldapUserDAO" class="com.trx.wfm.model.dao.LdapUserDAO">
          <property name="ldapTemplate" ref="ldapTemplate" />
          <property name="ldapReadonly" value="${ldap.readonly}" />
          <property name="ldapBase" value="${ldap.base}" />
          </bean>

          ldap.url=ldaps://host:636
          ldap.user.base=
          ldap.base=OU=TRX DEV,OU=WFM LDAP,OU=External Clients,DC=trxfs,DC=trx,DC=com
          ldap.admin.bind.userdn=CN=xxxxxx,OU=WFM LDAP,OU=External Clients,DC=trxfs,DC=trx,DC=com

          Comment


          • #6
            UNIT test

            public void test_1_CreateAndChangePassword() {

            LdapUserDAO ldap = (LdapUserDAO)applicationContext.getBean("ldapUserD AO");

            User user = new User();
            user.setUserId(1001);
            user.setEmailAddress("[email protected]");
            user.setFirstName( "Testing" );
            user.setLastName( "Account" );
            user.setPassword( "c0mpl3xp@s" );

            try {

            ldap.createUser(user);

            user.setPassword( "c1mp24xp#s" );

            ldap.changePassword(user);

            LdapAuthenticationProvider ldapProvider = (LdapAuthenticationProvider)applicationContext.get Bean("ldapProvider");
            Authentication auth = new UsernamePasswordAuthenticationToken(user.getEmailA ddress(), user.getPassword());
            auth = ldapProvider.authenticate(auth);

            } catch ( Exception exc ) {
            exc.printStackTrace();
            fail( exc.getMessage() );
            }
            }

            Comment


            • #7
              public Principal doAuthentication(String username, Object credentials) {
              Authentication auth = new UsernamePasswordAuthenticationToken(username, credentials);
              String password = (String) credentials;
              if (password == null || password.length() < 8) {
              SecurityException sex = new SecurityException();
              sex.setMessage("invalid password");
              throw sex;
              }

              try {
              // org.springframework.security.providers.ldap.LdapAu thenticationProvider
              auth = ldapProvider.authenticate(auth);
              // } catch (AuthenticationException ex) {
              } catch (Exception ex) {
              ex.printStackTrace();
              SecurityException sex = new SecurityException();
              sex.setMessage( ex.getMessage() );
              sex.initCause(ex);
              sex.setDetails(ex.getMessage());
              sex.setCode(SecurityException.CLIENT_AUTHENTICATIO N_CODE);
              throw sex;
              }

              try {
              User user = userdao.findByEmail(username);
              FlexSession session = FlexContext.getFlexSession();
              session.setAttribute(WfmConstants.WFM_USER , user);
              } catch (Exception ex) {
              SecurityException sex = new SecurityException();
              sex.initCause(ex);
              sex.setMessage("user in ldap, but not WFM database");
              throw sex;
              }

              return new UserPrincipal(auth.getName());

              }

              Comment

              Working...
              X