0

I have an Application with JSF 2.0 and Spring 3.1.X with Spring Security. This is what I have done so far, what I want is to create a Custom Spring Authentication with an encrypted password save in the mysql database. I wanted to use BCryptPasswordEncoder to encrypt my password. This is what I have in my web.xml

  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

This is what I have in my spring Security configuration file which is security-context.xml

<sec:global-method-security pre-post-annotations="enabled" />
<sec:http auto-config="true" use-expressions="true" access-denied-page="/pages/unsecure/accessDenied.xhtml">

    <sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" />

    <sec:intercept-url pattern="/ccrxhtml/**" access="hasRole('ROLE_USER')" />



    <sec:intercept-url pattern="/pages/unsecure" access="permitAll"/>


    <sec:intercept-url pattern="/resources/bootstrap/js/plugins/ckeditor/plugins/link/images/hidpi" access="hasRole('ROLE_MODERATOR')"/>

    <sec:intercept-url pattern="/javax.faces.resource/**" access="permitAll"/>

    <sec:form-login login-page="/pages/unsecure/loginForm.xhtml"
                    authentication-failure-url="/pages/unsecure/loginForm.xhtml?login_error=t"/>

    <sec:logout invalidate-session="true" delete-cookies="true" logout-success-url="/"></sec:logout>
</sec:http>


<beans:bean id="customUserDetailsService" class="com.xgen.ccr.service.impl.CustomUserDetailsService"/>

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider user-service-ref="customUserDetailsService">
        <sec:password-encoder ref="encoder"></sec:password-encoder>
    </sec:authentication-provider>
</sec:authentication-manager>

<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    <beans:constructor-arg name="strength" value="10" />
</beans:bean>

<beans:bean id="authProvider"
      class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <beans:property name="userDetailsService" ref="customUserDetailsService" />
    <beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>

This is the login form, which is loginForm.xhtml

<h:form id="loginForm">
            <div class="login_field">


                <h:graphicImage library="images" name="connect121-1.jpg" styleClass="login_image" />
                <p:growl id="msg" showDetail="true" life="3000" />
                <p:panel header="Login" style="width: 100%;">

                    <h:panelGrid id="loginPanel" columns="2">
                        <h:outputText value="Username" />

                        <p:inputText id="j_username" value="#{loginMgmtBean.userName}"
                                     required="true" requiredMessage="Please enter a UserName"></p:inputText>

                        <p:spacer></p:spacer>

                        <p:message for="j_username" ></p:message>

                        <h:outputText value="Password" />

                        <p:password id="j_password" value="#{loginMgmtBean.password}"   feedback="false"
                                    required="true" requiredMessage="Please enter a password"></p:password>

                        <p:spacer></p:spacer>

                        <p:message for="j_password"></p:message>

                    </h:panelGrid>

                    <h:commandButton value="Sign Me In"
                                     action="#{loginMgmtBean.login}"
                                     update="loginForm"
                                     styleClass="button_login"
                                     ajax="true"/>

This is my LoginMgtManageBean.java the login mathod which implements UserDetailsService interface.

public String login()
{
    try
    {

        boolean userExists = userService.login(userName, password);
        if (userExists)
        {
            user = userService.findByUserName(userName);
            getCurrentHttpSession().setAttribute("userName", userName);

        }
        Authentication request  = new UsernamePasswordAuthenticationToken(this.getUserName(), this.getPassword());
        //authenticationManager is defined in line number 46 to 50
        Authentication result   = authenticationManager.authenticate(request);//Will return a validated authentication object
        SecurityContextHolder.getContext().setAuthentication(result);


    }
    catch (AuthenticationServiceException e)
    {
        FacesContext.getCurrentInstance().addMessage("test",new FacesMessage(FacesMessage.SEVERITY_FATAL,
                "Invalid Login - User not found!","Please Try Again!"));


        return "incorrect";
    }
    return "correct";
}

This is the CustomUserDetails which I am using,

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    com.xgen.ccr.entity.User domainUser = userService.findByUserName(userName);

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    if (domainUser == null) {
        return null;
    }
    User userToReturn = new User(domainUser.getUserName(), domainUser.getPassword(), enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, getAuthorities(domainUser.getRole().getId()));
    return userToReturn;
}

Just want to know the what I am missing ? Can any direct me to a accurate guide for this Well, the problem I have is I inserted a user in to my mysql database with an encrypted password with the expectation that I will be able to login with that user

   User user = new User();
        Role roleById = roleService.findRoleById(1l);
        user.setFirstName("Ajith");
        user.setUserName("ranga");

        BCryptPasswordEncoder   passwordEncoder = new BCryptPasswordEncoder();
        String                  hashedPassword  = passwordEncoder.encode("333333");
        user.setPassword(hashedPassword);
        user.setRole(roleById);
        userService.saveUser(user);

, yet the application simply does not authenticate the user with username/password ranga/333333

These are my tables

  1. User(userid,username,password,firstName)
  2. Role(roleid,role_name,description)
  3. user_role(roleid,userid) composite primary key

I have the three tables alltogether, User, Role, and user_role which have the userid and the roldid init. This is my role table

CREATE TABLE `USER_ROLES` (
  `role_id` bigint(20) NOT NULL DEFAULT '0',
  `user_id` bigint(20) NOT NULL,
  PRIMARY KEY (`role_id`,`user_id`),
  UNIQUE KEY `UK_690fxih6hbwaxrgl1rlfs37ko` (`user_id`),
  KEY `FK_2pe93gfsv15g0fdrcfpv4hapu` (`role_id`),
  KEY `FK_690fxih6hbwaxrgl1rlfs37ko` (`user_id`),
  CONSTRAINT `FK_2pe93gfsv15g0fdrcfpv4hapu` FOREIGN KEY (`role_id`) REFERENCES `Roles` (`id`),
  CONSTRAINT `FK_690fxih6hbwaxrgl1rlfs37ko` FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
Smern
  • 18,746
  • 21
  • 72
  • 90
  • 1
    And the problems is...? – Boris the Spider Apr 17 '15 at 07:31
  • The problem is I entered a user with an encrypted password as below `BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String hashedPassword = passwordEncoder.encode("333333"); boolean matches = passwordEncoder.matches("333333", hashedPassword); user.setPassword(hashedPassword);` And when I try to login it simply does not authenticate the user – Rashendra - Rashen Apr 17 '15 at 07:58
  • Below where? I don't understand. In your question, clarify exactly what isn't working. – Boris the Spider Apr 17 '15 at 07:58
  • I just added a user with an encrypted password to the database. The username/password is ranga/33333 and the encrypted password is saved to the database such as $2a$10$TJGsOQCPi6G6kNVLNNlKWu69laomgRl.piMWaaLfhJwyDwA6kjcK. So, with the above custom authentication I tried to login with ranga/333333 yet it does not authenticate that user – Rashendra - Rashen Apr 17 '15 at 08:06
  • **In your question**, clarify exactly what isn't working. – Boris the Spider Apr 17 '15 at 08:07
  • can you post your db table for authorities – QGA Apr 17 '15 at 09:11
  • yes, I have further clarify whats my problem.. Thanks any help on this? – Rashendra - Rashen Apr 17 '15 at 09:11
  • Posted in the question. Edited the question – Rashendra - Rashen Apr 17 '15 at 09:14
  • If authentication fails, you should get a relevant message from Spring Security. Is there any message? I have ever done the same thing [here](http://stackoverflow.com/q/20919913/1391249). The question contains how it was done. The question itself however, was targeted to yield different answer(s). Therefore, answers are completely unrelated. – Tiny Apr 17 '15 at 11:30
  • I hope I'm not being to pedantic but you're _hashing_, not _encrypting_ the passwords. Don't worry, this is probably what you want. – Neil Smithline Apr 17 '15 at 18:15
  • This is what the framework expects - `BCryptPasswordEncoder#encode(CharSequence rawPassword);`. @NeilSmithline – Tiny Apr 17 '15 at 18:56
  • Not sure what you're saying @Tiny. My only point was that BCrypt does hashing, not encryption. – Neil Smithline Apr 17 '15 at 23:10
  • There is inherently nothing wrong in the OP's code (`BCryptPasswordEncoder#encode(CharSequence rawPassword);` is the correct way to go). @NeilSmithline – Tiny Apr 17 '15 at 23:18
  • Ahh. I was commenting that the title and text use the word "encrypt" rather than "hash". – Neil Smithline Apr 17 '15 at 23:20
  • Guys , i just used encrypt as my intention was to use BCryptPasswordEncoder, can anyone direct me to a good guide, all I want is this. 1. Save a encrypted password to the database 2. Configurations needed 3. How the password is transformed from the xhtml page – Rashendra - Rashen Apr 18 '15 at 03:47

1 Answers1

0

This was fixed using the following encryption mechanism in Spring security In Spring-security.xml

    <beans:bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    <beans:constructor-arg name="strength" value="12"/>
</beans:bean>


<!-- Set customUserDetailsService class as the authentication Manager for Spring Security-->
<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider user-service-ref="customUserDetailsService" >
        <sec:password-encoder ref="bCryptPasswordEncoder"></sec:password-encoder>
    </sec:authentication-provider>
</sec:authentication-manager>

Also in the CustomUserDetailsService.java you just need to override the loadUserByuserName

@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
    com.xgen.ccr.entity.User domainUser = userService.findByUserName(userName);

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    if (domainUser == null) {
        return null;
    }
    User userToReturn = new User(domainUser.getUserName(), domainUser.getPassword(), enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, getAuthorities(domainUser.getRole().getId()));
    return userToReturn;
}

Also when you are creating a user please use the same strength

 User user = new User();
    Role roleById = roleService.findRoleById(1l);
    user.setFirstName("chandana1");
    user.setUserName("chandana1");
    user.setEnabled(Boolean.TRUE);

    BCryptPasswordEncoder   passwordEncoder = new BCryptPasswordEncoder(12);
    String                  hashedPassword  = passwordEncoder.encode("333333");

    boolean matches = passwordEncoder.matches("333333", hashedPassword);
    System.out.println(matches);

    user.setPassword(hashedPassword);

finally set the prependId to false in the login form

<h:form id="loginForm" prependId="false">

This will not append the form id to the j_username and j_password.

Further, do the necessary navigation as above.

Hope this would help someone who wants to use 1. Custom JSF login page 2. Use spring security with password encryption/hashing using BcryptPasswordEncoder 3. Want to load the password from the database(Hibernate as the ORM)