View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.security.kim;
17  
18  import org.kuali.student.security.spring.KSRiceDefaultUserDetailsService;
19  
20  import org.springframework.dao.DataAccessException;
21  import org.springframework.security.authentication.AuthenticationProvider;
22  import org.springframework.security.authentication.AuthenticationServiceException;
23  import org.springframework.security.authentication.BadCredentialsException;
24  import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
25  import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
26  import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
27  import org.springframework.security.authentication.dao.SaltSource;
28  import org.springframework.security.authentication.encoding.PasswordEncoder;
29  import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
30  import org.springframework.security.core.AuthenticationException;
31  import org.springframework.security.core.userdetails.UserDetails;
32  import org.springframework.security.core.userdetails.UserDetailsService;
33  import org.springframework.util.Assert;
34  
35  
36  /**
37   * An {@link AuthenticationProvider} implementation that retrieves user details
38   * from an {@link UserDetailsService}. Slightly modified from {@link DaoAuthenticationProvider}
39   * 
40   * @author Kuali Student Team
41   *
42   */
43  public class KimAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
44      
45      //~ Instance fields ================================================================================================
46  
47      private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
48  
49      private SaltSource saltSource;
50  
51      private UserDetailsService userDetailsService;
52  
53      private boolean includeDetailsObject = true;
54  
55      //~ Methods ========================================================================================================
56  
57      protected void additionalAuthenticationChecks(UserDetails userDetails,
58              UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
59          Object salt = null;
60          if (this.saltSource != null) {
61              salt = this.saltSource.getSalt(userDetails);
62          }
63  
64          if (authentication.getCredentials() == null) {
65              throw new BadCredentialsException(messages.getMessage(
66                      "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
67                      includeDetailsObject ? userDetails : null);
68          }
69  
70          String presentedPassword = authentication.getCredentials().toString();
71  
72          if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
73              throw new BadCredentialsException(messages.getMessage(
74                      "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
75                      includeDetailsObject ? userDetails : null);
76          }
77      }
78  
79      protected void doAfterPropertiesSet() throws Exception {
80          Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
81      }
82  
83      protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
84              throws AuthenticationException {
85          UserDetails loadedUser;
86  
87          UserDetailsService ksRiceDefaultUserDetailsService = this.getUserDetailsService();
88          if(!(ksRiceDefaultUserDetailsService instanceof KSRiceDefaultUserDetailsService)){
89              throw new AuthenticationServiceException(
90                  "UserDetailsService is not an an instance of KSRiceDefaultUserDetailsService");
91          }
92          
93          try {
94              //loadedUser = this.getUserDetailsService().loadUserByUsername(username);
95              loadedUser = ((KSRiceDefaultUserDetailsService)ksRiceDefaultUserDetailsService).loadUserByUsernameAndToken(username, authentication);
96          }
97          catch (DataAccessException repositoryProblem) {
98              throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
99          }
100 
101         if (loadedUser == null) {
102             throw new AuthenticationServiceException(
103                     "UserDetailsService returned null, which is an interface contract violation");
104         }
105         return loadedUser;
106     }
107 
108     /**
109      * Sets the PasswordEncoder instance to be used to encode and validate passwords.
110      * If not set, {@link PlaintextPasswordEncoder} will be used by default.
111      *
112      * @param passwordEncoder The passwordEncoder to use
113      */
114     public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
115         this.passwordEncoder = passwordEncoder;
116     }
117 
118     protected PasswordEncoder getPasswordEncoder() {
119         return passwordEncoder;
120     }
121 
122     /**
123      * The source of salts to use when decoding passwords. <code>null</code>
124      * is a valid value, meaning the <code>DaoAuthenticationProvider</code>
125      * will present <code>null</code> to the relevant <code>PasswordEncoder</code>.
126      *
127      * @param saltSource to use when attempting to decode passwords via the <code>PasswordEncoder</code>
128      */
129     public void setSaltSource(SaltSource saltSource) {
130         this.saltSource = saltSource;
131     }
132 
133     protected SaltSource getSaltSource() {
134         return saltSource;
135     }
136 
137     public void setUserDetailsService(UserDetailsService userDetailsService) {
138         this.userDetailsService = userDetailsService;
139     }
140 
141     protected UserDetailsService getUserDetailsService() {
142         return userDetailsService;
143     }
144 
145     protected boolean isIncludeDetailsObject() {
146         return includeDetailsObject;
147     }
148 }