View Javadoc

1   /* Copyright 2004, 2005 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.acegisecurity.providers.dao;
17  
18  import org.acegisecurity.AuthenticationException;
19  import org.acegisecurity.AuthenticationServiceException;
20  import org.acegisecurity.BadCredentialsException;
21  
22  import org.acegisecurity.providers.AuthenticationProvider;
23  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
24  import org.acegisecurity.providers.encoding.PasswordEncoder;
25  import org.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
26  import org.acegisecurity.userdetails.UserDetailsService;
27  import org.acegisecurity.userdetails.UserDetails;
28  import org.acegisecurity.userdetails.UsernameNotFoundException;
29  
30  import org.springframework.dao.DataAccessException;
31  
32  import org.springframework.util.Assert;
33  
34  
35  /***
36   * An {@link AuthenticationProvider} implementation that retrieves user details
37   * from an {@link UserDetailsService}.
38   */
39  public class DaoAuthenticationProvider
40      extends AbstractUserDetailsAuthenticationProvider {
41      //~ Instance fields ========================================================
42  
43      private UserDetailsService userDetailsService;
44      private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
45      private SaltSource saltSource;
46      private boolean hideUserNotFoundExceptions = true;
47  
48      //~ Methods ================================================================
49  
50      protected void additionalAuthenticationChecks(UserDetails userDetails,
51          UsernamePasswordAuthenticationToken authentication)
52          throws AuthenticationException {
53          Object salt = null;
54  
55          if (this.saltSource != null) {
56              salt = this.saltSource.getSalt(userDetails);
57          }
58  
59          if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
60                  authentication.getCredentials().toString(), salt)) {
61              throw new BadCredentialsException(messages.getMessage(
62                      "AbstractUserDetailsAuthenticationProvider.badCredentials",
63                      "Bad credentials"), userDetails);
64          }
65      }
66  
67      protected void doAfterPropertiesSet() throws Exception {
68          Assert.notNull(this.userDetailsService,
69              "An Authentication DAO must be set");
70      }
71  
72      public UserDetailsService getUserDetailsService() {
73          return userDetailsService;
74      }
75  
76      public PasswordEncoder getPasswordEncoder() {
77          return passwordEncoder;
78      }
79  
80      public SaltSource getSaltSource() {
81          return saltSource;
82      }
83  
84      public boolean isHideUserNotFoundExceptions() {
85          return hideUserNotFoundExceptions;
86      }
87  
88      protected final UserDetails retrieveUser(String username,
89          UsernamePasswordAuthenticationToken authentication)
90          throws AuthenticationException {
91          UserDetails loadedUser;
92  
93          try {
94              loadedUser = this.userDetailsService.loadUserByUsername(username);
95          } catch (UsernameNotFoundException notFound) {
96              if (hideUserNotFoundExceptions) {
97                  throw new BadCredentialsException(messages.getMessage(
98                          "AbstractUserDetailsAuthenticationProvider.badCredentials",
99                          "Bad credentials"));
100             } else {
101                 throw notFound;
102             }
103         } catch (DataAccessException repositoryProblem) {
104             throw new AuthenticationServiceException(repositoryProblem
105                     .getMessage(), repositoryProblem);
106             }
107 
108             if (loadedUser == null) {
109                 throw new AuthenticationServiceException(
110                     "AuthenticationDao returned null, which is an interface contract violation");
111             }
112 
113             return loadedUser;
114         }
115 
116         public void setUserDetailsService(UserDetailsService authenticationDao) {
117             this.userDetailsService = authenticationDao;
118         }
119 
120         /***
121          * By default the <code>DaoAuthenticationProvider</code> throws a
122          * <code>BadCredentialsException</code> if a username is not found or
123          * the password is incorrect. Setting this property to
124          * <code>false</code> will cause
125          * <code>UsernameNotFoundException</code>s to be thrown instead for
126          * the former. Note this is considered less secure than throwing
127          * <code>BadCredentialsException</code> for both exceptions.
128          *
129          * @param hideUserNotFoundExceptions set to <code>false</code> if you
130          *        wish <code>UsernameNotFoundException</code>s to be thrown
131          *        instead of the non-specific
132          *        <code>BadCredentialsException</code> (defaults to
133          *        <code>true</code>)
134          */
135         public void setHideUserNotFoundExceptions(
136             boolean hideUserNotFoundExceptions) {
137             this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
138         }
139 
140         /***
141          * Sets the PasswordEncoder instance to be used to encode and validate
142          * passwords. If not set, {@link PlaintextPasswordEncoder} will be
143          * used by default.
144          *
145          * @param passwordEncoder The passwordEncoder to use
146          */
147         public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
148             this.passwordEncoder = passwordEncoder;
149         }
150 
151         /***
152          * The source of salts to use when decoding passwords.
153          * <code>null</code> is a valid value, meaning the
154          * <code>DaoAuthenticationProvider</code> will present
155          * <code>null</code> to the relevant <code>PasswordEncoder</code>.
156          *
157          * @param saltSource to use when attempting to decode passwords via the
158          *        <code>PasswordEncoder</code>
159          */
160         public void setSaltSource(SaltSource saltSource) {
161             this.saltSource = saltSource;
162         }
163     }