1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.providers.x509;
17
18 import java.security.cert.X509Certificate;
19
20 import org.acegisecurity.AcegiMessageSource;
21 import org.acegisecurity.Authentication;
22 import org.acegisecurity.AuthenticationException;
23 import org.acegisecurity.BadCredentialsException;
24 import org.acegisecurity.providers.AuthenticationProvider;
25 import org.acegisecurity.providers.x509.cache.NullX509UserCache;
26 import org.acegisecurity.userdetails.UserDetails;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.springframework.beans.factory.InitializingBean;
30 import org.springframework.context.MessageSource;
31 import org.springframework.context.MessageSourceAware;
32 import org.springframework.context.support.MessageSourceAccessor;
33 import org.springframework.util.Assert;
34
35
36 /***
37 * Processes an X.509 authentication request.
38 *
39 * <p>
40 * The request will typically originate from {@link
41 * org.acegisecurity.ui.x509.X509ProcessingFilter}).
42 * </p>
43 */
44 public class X509AuthenticationProvider implements AuthenticationProvider,
45 InitializingBean, MessageSourceAware {
46
47
48 private static final Log logger = LogFactory.getLog(X509AuthenticationProvider.class);
49
50
51
52 protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
53 private X509AuthoritiesPopulator x509AuthoritiesPopulator;
54 private X509UserCache userCache = new NullX509UserCache();
55
56
57
58 public void afterPropertiesSet() throws Exception {
59 Assert.notNull(userCache, "An x509UserCache must be set");
60 Assert.notNull(x509AuthoritiesPopulator,
61 "An X509AuthoritiesPopulator must be set");
62 Assert.notNull(this.messages, "A message source must be set");
63 }
64
65 /***
66 * If the supplied authentication token contains a certificate then this
67 * will be passed to the configured {@link X509AuthoritiesPopulator} to
68 * obtain the user details and authorities for the user identified by the
69 * certificate.
70 *
71 * <p>
72 * If no certificate is present (for example, if the filter is applied to
73 * an HttpRequest for which client authentication hasn't been configured
74 * in the container) then a BadCredentialsException will be raised.
75 * </p>
76 *
77 * @param authentication the authentication request.
78 *
79 * @return an X509AuthenticationToken containing the authorities of the
80 * principal represented by the certificate.
81 *
82 * @throws AuthenticationException if the {@link X509AuthoritiesPopulator}
83 * rejects the certficate.
84 * @throws BadCredentialsException if no certificate was presented in the
85 * authentication request.
86 */
87 public Authentication authenticate(Authentication authentication)
88 throws AuthenticationException {
89 if (!supports(authentication.getClass())) {
90 return null;
91 }
92
93 if (logger.isDebugEnabled()) {
94 logger.debug("X509 authentication request: " + authentication);
95 }
96
97 X509Certificate clientCertificate = (X509Certificate) authentication
98 .getCredentials();
99
100 if (clientCertificate == null) {
101 throw new BadCredentialsException(messages.getMessage(
102 "X509AuthenticationProvider.certificateNull",
103 "Certificate is null"));
104 }
105
106 UserDetails user = userCache.getUserFromCache(clientCertificate);
107
108 if (user == null) {
109 logger.debug("Authenticating with certificate "
110 + clientCertificate);
111 user = x509AuthoritiesPopulator.getUserDetails(clientCertificate);
112 userCache.putUserInCache(clientCertificate, user);
113 }
114
115 return new X509AuthenticationToken(user, clientCertificate,
116 user.getAuthorities());
117 }
118
119 public void setMessageSource(MessageSource messageSource) {
120 this.messages = new MessageSourceAccessor(messageSource);
121 }
122
123 public void setX509AuthoritiesPopulator(
124 X509AuthoritiesPopulator x509AuthoritiesPopulator) {
125 this.x509AuthoritiesPopulator = x509AuthoritiesPopulator;
126 }
127
128 public void setX509UserCache(X509UserCache cache) {
129 this.userCache = cache;
130 }
131
132 public boolean supports(Class authentication) {
133 return X509AuthenticationToken.class.isAssignableFrom(authentication);
134 }
135 }