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.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      //~ Static fields/initializers =============================================
    47
    48      private static final Log logger = LogFactory.getLog(X509AuthenticationProvider.class);
    49
    50      //~ Instance fields ========================================================
    51
    52      protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
    53      private X509AuthoritiesPopulator x509AuthoritiesPopulator;
    54      private X509UserCache userCache = new NullX509UserCache();
    55
    56      //~ Methods ================================================================
    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     }