001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.providers.x509;
017:
018: import org.acegisecurity.AcegiMessageSource;
019: import org.acegisecurity.Authentication;
020: import org.acegisecurity.AuthenticationException;
021: import org.acegisecurity.BadCredentialsException;
022:
023: import org.acegisecurity.providers.AuthenticationProvider;
024: import org.acegisecurity.providers.x509.cache.NullX509UserCache;
025:
026: import org.acegisecurity.userdetails.UserDetails;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.springframework.beans.factory.InitializingBean;
032:
033: import org.springframework.context.MessageSource;
034: import org.springframework.context.MessageSourceAware;
035: import org.springframework.context.support.MessageSourceAccessor;
036:
037: import org.springframework.util.Assert;
038:
039: import java.security.cert.X509Certificate;
040:
041: /**
042: * Processes an X.509 authentication request.<p>The request will typically originate from {@link
043: * org.acegisecurity.ui.x509.X509ProcessingFilter}).</p>
044: *
045: * @author Luke Taylor
046: * @version $Id: X509AuthenticationProvider.java 1948 2007-08-25 00:15:30Z benalex $
047: */
048: public class X509AuthenticationProvider implements
049: AuthenticationProvider, InitializingBean, MessageSourceAware {
050: //~ Static fields/initializers =====================================================================================
051:
052: private static final Log logger = LogFactory
053: .getLog(X509AuthenticationProvider.class);
054:
055: //~ Instance fields ================================================================================================
056:
057: protected MessageSourceAccessor messages = AcegiMessageSource
058: .getAccessor();
059: private X509AuthoritiesPopulator x509AuthoritiesPopulator;
060: private X509UserCache userCache = new NullX509UserCache();
061:
062: //~ Methods ========================================================================================================
063:
064: public void afterPropertiesSet() throws Exception {
065: Assert.notNull(userCache, "An x509UserCache must be set");
066: Assert.notNull(x509AuthoritiesPopulator,
067: "An X509AuthoritiesPopulator must be set");
068: Assert.notNull(this .messages, "A message source must be set");
069: }
070:
071: /**
072: * If the supplied authentication token contains a certificate then this will be passed to the configured
073: * {@link X509AuthoritiesPopulator} to obtain the user details and authorities for the user identified by the
074: * certificate.<p>If no certificate is present (for example, if the filter is applied to an HttpRequest for
075: * which client authentication hasn't been configured in the container) then a BadCredentialsException will be
076: * raised.</p>
077: *
078: * @param authentication the authentication request.
079: *
080: * @return an X509AuthenticationToken containing the authorities of the principal represented by the certificate.
081: *
082: * @throws AuthenticationException if the {@link X509AuthoritiesPopulator} rejects the certficate.
083: * @throws BadCredentialsException if no certificate was presented in the authentication request.
084: */
085: public Authentication authenticate(Authentication authentication)
086: throws AuthenticationException {
087: if (!supports(authentication.getClass())) {
088: return null;
089: }
090:
091: if (logger.isDebugEnabled()) {
092: logger.debug("X509 authentication request: "
093: + authentication);
094: }
095:
096: X509Certificate clientCertificate = (X509Certificate) authentication
097: .getCredentials();
098:
099: if (clientCertificate == null) {
100: throw new BadCredentialsException(messages.getMessage(
101: "X509AuthenticationProvider.certificateNull",
102: "Certificate is null"));
103: }
104:
105: UserDetails user = userCache
106: .getUserFromCache(clientCertificate);
107:
108: if (user == null) {
109: logger.debug("Authenticating with certificate "
110: + clientCertificate);
111: user = x509AuthoritiesPopulator
112: .getUserDetails(clientCertificate);
113: userCache.putUserInCache(clientCertificate, user);
114: }
115:
116: X509AuthenticationToken result = new X509AuthenticationToken(
117: user, clientCertificate, user.getAuthorities());
118:
119: result.setDetails(authentication.getDetails());
120:
121: return result;
122: }
123:
124: public void setMessageSource(MessageSource messageSource) {
125: this .messages = new MessageSourceAccessor(messageSource);
126: }
127:
128: public void setX509AuthoritiesPopulator(
129: X509AuthoritiesPopulator x509AuthoritiesPopulator) {
130: this .x509AuthoritiesPopulator = x509AuthoritiesPopulator;
131: }
132:
133: public void setX509UserCache(X509UserCache cache) {
134: this .userCache = cache;
135: }
136:
137: public boolean supports(Class authentication) {
138: return X509AuthenticationToken.class
139: .isAssignableFrom(authentication);
140: }
141: }
|