View Javadoc

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