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.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      //~ Instance fields ========================================================
    42
    43      private UserDetailsService userDetailsService;
    44      private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
    45      private SaltSource saltSource;
    46      private boolean hideUserNotFoundExceptions = true;
    47
    48      //~ Methods ================================================================
    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     }