1
2
3
4
5
6
7
8
9
10
11
12
13
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
42
43 private UserDetailsService userDetailsService;
44 private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
45 private SaltSource saltSource;
46 private boolean hideUserNotFoundExceptions = true;
47
48
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 }