1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.security.providers.dao;
17
18 import org.springframework.security.AccountExpiredException;
19 import org.springframework.security.SpringSecurityMessageSource;
20 import org.springframework.security.Authentication;
21 import org.springframework.security.AuthenticationException;
22 import org.springframework.security.BadCredentialsException;
23 import org.springframework.security.CredentialsExpiredException;
24 import org.springframework.security.DisabledException;
25 import org.springframework.security.LockedException;
26
27 import org.springframework.security.providers.AuthenticationProvider;
28 import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
29 import org.springframework.security.providers.dao.cache.NullUserCache;
30
31 import org.springframework.security.userdetails.UserDetails;
32 import org.springframework.security.userdetails.UserDetailsService;
33 import org.springframework.security.userdetails.UsernameNotFoundException;
34 import org.springframework.security.userdetails.UserDetailsChecker;
35
36 import org.springframework.beans.factory.InitializingBean;
37
38 import org.springframework.context.MessageSource;
39 import org.springframework.context.MessageSourceAware;
40 import org.springframework.context.support.MessageSourceAccessor;
41
42 import org.springframework.util.Assert;
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 public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean,
70 MessageSourceAware {
71
72
73 protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
74 private UserCache userCache = new NullUserCache();
75 private boolean forcePrincipalAsString = false;
76 protected boolean hideUserNotFoundExceptions = true;
77 private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
78 private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
97 UsernamePasswordAuthenticationToken authentication)
98 throws AuthenticationException;
99
100 public final void afterPropertiesSet() throws Exception {
101 Assert.notNull(this.userCache, "A user cache must be set");
102 Assert.notNull(this.messages, "A message source must be set");
103 doAfterPropertiesSet();
104 }
105
106 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
107 Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
108 messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
109 "Only UsernamePasswordAuthenticationToken is supported"));
110
111
112 String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
113
114 boolean cacheWasUsed = true;
115 UserDetails user = this.userCache.getUserFromCache(username);
116
117 if (user == null) {
118 cacheWasUsed = false;
119
120 try {
121 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
122 } catch (UsernameNotFoundException notFound) {
123 if (hideUserNotFoundExceptions) {
124 throw new BadCredentialsException(messages.getMessage(
125 "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
126 } else {
127 throw notFound;
128 }
129 }
130
131 Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
132 }
133
134 preAuthenticationChecks.check(user);
135
136 try {
137 additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
138 } catch (AuthenticationException exception) {
139 if (cacheWasUsed) {
140
141
142 cacheWasUsed = false;
143 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
144 additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
145 } else {
146 throw exception;
147 }
148 }
149
150 postAuthenticationChecks.check(user);
151
152 if (!cacheWasUsed) {
153 this.userCache.putUserInCache(user);
154 }
155
156 Object principalToReturn = user;
157
158 if (forcePrincipalAsString) {
159 principalToReturn = user.getUsername();
160 }
161
162 return createSuccessAuthentication(principalToReturn, authentication, user);
163 }
164
165
166
167
168
169
170
171
172
173
174
175
176
177 protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
178 UserDetails user) {
179
180
181
182
183 UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
184 authentication.getCredentials(), user.getAuthorities());
185 result.setDetails(authentication.getDetails());
186
187 return result;
188 }
189
190 protected void doAfterPropertiesSet() throws Exception {}
191
192 public UserCache getUserCache() {
193 return userCache;
194 }
195
196 public boolean isForcePrincipalAsString() {
197 return forcePrincipalAsString;
198 }
199
200 public boolean isHideUserNotFoundExceptions() {
201 return hideUserNotFoundExceptions;
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 protected abstract UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
233 throws AuthenticationException;
234
235 public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
236 this.forcePrincipalAsString = forcePrincipalAsString;
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250 public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
251 this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
252 }
253
254 public void setMessageSource(MessageSource messageSource) {
255 this.messages = new MessageSourceAccessor(messageSource);
256 }
257
258 public void setUserCache(UserCache userCache) {
259 this.userCache = userCache;
260 }
261
262 public boolean supports(Class authentication) {
263 return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
264 }
265
266 protected UserDetailsChecker getPreAuthenticationChecks() {
267 return preAuthenticationChecks;
268 }
269
270
271
272
273
274
275
276 public void setPreAuthenticationChecks(UserDetailsChecker preAuthenticationChecks) {
277 this.preAuthenticationChecks = preAuthenticationChecks;
278 }
279
280 protected UserDetailsChecker getPostAuthenticationChecks() {
281 return postAuthenticationChecks;
282 }
283
284 public void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks) {
285 this.postAuthenticationChecks = postAuthenticationChecks;
286 }
287
288 private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
289 public void check(UserDetails user) {
290 if (!user.isAccountNonLocked()) {
291 throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
292 "User account is locked"), user);
293 }
294
295 if (!user.isEnabled()) {
296 throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
297 "User is disabled"), user);
298 }
299
300 if (!user.isAccountNonExpired()) {
301 throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
302 "User account has expired"), user);
303 }
304 }
305 }
306
307 private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
308 public void check(UserDetails user) {
309 if (!user.isCredentialsNonExpired()) {
310 throw new CredentialsExpiredException(messages.getMessage(
311 "AbstractUserDetailsAuthenticationProvider.credentialsExpired",
312 "User credentials have expired"), user);
313 }
314 }
315 }
316 }