LoginController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//signup
@RequestMapping(value = {"/authentication/process_create_user"})
    public String processCreateUser(@ModelAttribute(value = "signupForm") @Valid SignUpForm signupForm, BindingResult result, Model model, HttpServletRequest request) {

        singupPasswordValidator.validate(signupForm, result);
        if (result.hasErrors()) {
            model.addAttribute("signupForm", signupForm);
            return "authentication/signup";
        }

        User existing = null;
        try {
            existing = userService.findByUsername(signupForm.getEmail());
        } catch (NoResultException nre) {
        }


        try {
            //TODO: uncomment when spring data commons conflit is solved



            if (existing != null) {
                model.addAttribute("msg", messageSource.getMessage("signup.controller.userexist", null, request.getLocale()));
                model.addAttribute("signupForm", signupForm);
                return "authentication/signup";
            }

            RandomNumberGenerator rng = new SecureRandomNumberGenerator();
            ByteSource salt = rng.nextBytes(10);              
            String hashedPasswordBase64 = new Sha256Hash(signupForm.getPassword(),salt).toBase64();

            userService.createUser(signupForm.getFullName(), signupForm.getEmail(), hashedPasswordBase64, salt.toBase64());

        } catch (Exception ex) {
            ex.getMessage();
        }

        return "authentication/success";
    }


 @RequestMapping(value = {"/authentication/processlogin"})
    public String processLogin(@ModelAttribute(value = "loginForm") @Valid LoginForm loginForm, BindingResult result, Model model, HttpServletRequest request) {
        String message ="";
        model.addAttribute("loginForm", loginForm);
        if (result.hasErrors()) {
            model.addAttribute("message", "");
            
            return "authentication/login";
        }

        try {
            Subject currentUser = SecurityUtils.getSubject();
            if (!currentUser.isAuthenticated()) {
                UsernamePasswordToken token = new UsernamePasswordToken(loginForm.getEmail(), loginForm.getPassword(), loginForm.isRememberMe());
                SecurityUtils.getSubject().login(token);
            }
        } catch (UnknownAccountException uae) {

            message = messageSource.getMessage("login.form.backend.checkcredential.message", null, request.getLocale());
            model.addAttribute("message", message);
            return "authentication/login";
            
        } catch (IncorrectCredentialsException ice) {
            message = messageSource.getMessage("login.form.backend.checkcredential.message", null, request.getLocale());
            model.addAttribute("message", message);
            return "authentication/login";
           
        } catch (LockedAccountException lae) {
            message = messageSource.getMessage("login.form.backend.accountlocked.message", null, request.getLocale());
            model.addAttribute("message", message);
            return "authentication/login";
           
        } catch (DisabledAccountException dae) {
            message = messageSource.getMessage("login.form.backend.accountdisabled.message", null, request.getLocale());
            model.addAttribute("message", message);
            return "authentication/login";
           
        } catch (AuthenticationException ae) {
            message = messageSource.getMessage("login.form.backend.authexception.message", null, request.getLocale());
            model.addAttribute("message", message);
            System.out.println(ae);
            ae.printStackTrace();
            return "authentication/login";
           
        } catch (Exception ex) {
            message = messageSource.getMessage("login.form.backend.authexception.message", null, request.getLocale());
            model.addAttribute("message", message);
             System.out.println(ex);
            ex.printStackTrace();
            return "authentication/login";
        }



        return "/dashboard";
    }

SaltedJPARealm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
public class SaltedJPARealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    

    @Autowired
    /* used to pick message from message_(lan).properties file to display appropriate i18n message*/
    MessageSource messageSource;

    public SaltedJPARealm() {
        setName("JPARealm");
    }

    public SaltedJPARealm(CredentialsMatcher matcher) {
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        if (token != null) {
            return (token instanceof UsernamePasswordToken);
        }
        return false;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        Set<String> stringRoles = new HashSet<String>();
        Set<Role> roles = new HashSet<Role>();
        Set<Right> rights = new HashSet<Right>();
        Set<String> permissions = new HashSet<String>();
        Collection<User> principalsList = pc.byType(User.class);

        if (principalsList.isEmpty()) {
            throw new AuthorizationException("Empty principals list!");
        }

        /*
         * principal has been set as user object itself.
         * this piece of code is to retrieve all the principals if applicable and get its roles.
         * Role in this case has a many-to-many relationship with user. From UserRole which is the
         * mapping of that many-to-many which we got from the user(principal) object we retrieve the list
         * of roles collection of the user.
         */
        for (User userPrincipal : principalsList) {

            Set<RoleUser> rles = userPrincipal.getUserRolesMap();
            for (RoleUser rUser : rles) {
                roles.add(rUser.getRole());
                stringRoles.add(rUser.getRole().getName());
            }
            
            /*
             * Role has a many-to-many with right mapped as entity RoleRight. this portion of code is to 
             * check for the size of the role collection and get the collection of RoleRight. for each RoleRight
             * we retrieve the right object and the right name appended to the set of permissions.
             */
            if (roles.size() > 0) {
                for (Role r : roles) {
                    Set<RoleRight> roleRights = r.getRoleRightMap();
                    for(RoleRight rr: roleRights){
                        rights.add(rr.getRight());
                        permissions.add(rr.getRight().getName());
                    }

                }
            }
            
            /*
             * There are special rights which grants users right which are not part of user's roles. On the
             * other way round it can deny rights which can be granted by any user's role. this section is to 
             * override the permission by checking whether a particular right in the UserRight mapping in the 
             * permission. If it is , it checks whether it's supposed to be denied or granted to the collection
             * of permissions.
             */
            Set<UserRight> userSpecialRights = userPrincipal.getUserRightMap();
            for(UserRight ur : userSpecialRights){
                if(ur.isAllowed()){
                    if(!permissions.contains(ur.getRight().getName()))
                        permissions.add(ur.getRight().getName());
                } else{
                if(permissions.contains(ur.getRight().getName())){
                    permissions.remove(ur.getRight().getName());
                }
                }
            }
//            
        }
        
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(stringRoles);
        info.setStringPermissions(permissions);
        return info;

    }

    @Override
    protected SaltedAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) at;

        //TODO: uncomment when spring data common conflit issues are solved  

       User user = getUserService().findByUsername(token.getUsername());
       if(user != null){
           if(!user.getIsActive()){
               throw new DisabledAccountException();
           }
           if(user.getIsLocked()){
               throw new LockedAccountException();
           }
           
           ByteSource salt = ByteSource.Util.bytes(user.getSalt());           
           return new SimpleAuthenticationInfo(user, user.getPassword().toCharArray(),salt,this.getName());
//           return new SimpleAuthenticationInfo(user, user.gSaltedAuthenticationInfoetPassword().toCharArray(),this.getName());
       } else {
           throw new UnknownAccountException();
       }

    }

    /**
     * @return the userService
     */
    public UserService getUserService() {
        return userService;
    }

    /**
     * @param userService the userService to set
     */
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

   
    
}

Sha256CredentialMatcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Sha256CredentialMatcher extends HashedCredentialsMatcher{
     public Sha256CredentialMatcher() {
        super();
//        this.setHashAlgorithmName(new Sha256Hash().getAlgorithmName());
 
    }
   
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info){

//        Object tokenfromSubmition = hashProvidedCredentials(token,info);
        Object tokenfromSubmition = hashProvidedCredentials(token.getCredentials(),((SaltedAuthenticationInfo)info).getCredentialsSalt(),0);
        Object passwordFromStorage =this.getCredentials(info);
        System.out.println("tokenFromSubmition ---------: " + tokenfromSubmition.toString());
        System.out.println("passwordFromStorage --------: "+ passwordFromStorage.toString());
            
        Boolean match = equals(tokenfromSubmition, passwordFromStorage);
        return match;
        
    } 
    
    
    private String charArrayToString(Object credentials) {
        return new String((char[]) credentials);
    }
    
    
}

security-applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 <bean id="saltedJPARealm" class="bla.bla.suite.webapp.security.SaltedJPARealm">
        <constructor-arg  ref="credMatcher"/>
    </bean>
    
        <bean id="credMatcher" class="bla.bla.suite.webapp.security.Sha256CredentialMatcher">
            <property name="storedCredentialsHexEncoded" value="false" />
            <property name="hashAlgorithmName" value="SHA-256" />
            <!--<property name="hashIterations" value="1024" />-->
        </bean>
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository">
        <property name="realm" ref="saltedJPARealm" />
    </bean>
 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
  
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
              <property name="proxyTargetClass" value="true" />
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!-- Secure Spring remoting:  Ensure any Spring Remoting method invocations can be associated
         with a Subject for security checks. -->
    <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!--<property name="loginUrl" value="/authentication/login" />-->
        <property name="loginUrl" value="/authentication/login" />
        <property name="successUrl" value="/dashboard" />
        <property name="unauthorizedUrl" value="/navigation/unauthorized" />
        <property name="filterChainDefinitions">
            <value>
            
            /authentication/** = anon
           
            </value>
        </property>
    </bean>