123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- package com.yihu.base.security.rbas.provider;
- import org.springframework.security.authentication.BadCredentialsException;
- import org.springframework.security.authentication.InternalAuthenticationServiceException;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
- import org.springframework.security.authentication.dao.SaltSource;
- import org.springframework.security.authentication.encoding.PasswordEncoder;
- import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
- import org.springframework.security.core.AuthenticationException;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.core.userdetails.UsernameNotFoundException;
- import org.springframework.util.Assert;
- /**
- * Created by 刘文彬 on 2018/6/1.
- */
- public class UserNamePasswordAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
- // ~ Static fields/initializers
- // =====================================================================================
- /**
- * The plaintext password used to perform
- * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
- * not found to avoid SEC-2056.
- */
- private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
- // ~ Instance fields
- // ================================================================================================
- private PasswordEncoder passwordEncoder;
- /**
- * The password used to perform
- * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when the user is
- * not found to avoid SEC-2056. This is necessary, because some
- * {@link PasswordEncoder} implementations will short circuit if the password is not
- * in a valid format.
- */
- private String userNotFoundEncodedPassword;
- private SaltSource saltSource;
- private UserDetailsService userDetailsService;
- public UserNamePasswordAuthenticationProvider() {
- setPasswordEncoder(new PlaintextPasswordEncoder());
- }
- // ~ Methods
- // ========================================================================================================
- @SuppressWarnings("deprecation")
- protected void additionalAuthenticationChecks(UserDetails userDetails,
- UsernamePasswordAuthenticationToken authentication)
- throws AuthenticationException {
- Object salt = null;
- if (this.saltSource != null) {
- salt = this.saltSource.getSalt(userDetails);
- }
- if (authentication.getCredentials() == null) {
- logger.debug("Authentication failed: no credentials provided");
- throw new BadCredentialsException(messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.badCredentials",
- "Bad credentials"));
- }
- String presentedPassword = authentication.getCredentials().toString();
- if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
- presentedPassword, salt)) {
- logger.debug("Authentication failed: password does not match stored value");
- throw new BadCredentialsException(messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.badCredentials",
- "Bad credentials"));
- }
- }
- protected void doAfterPropertiesSet() throws Exception {
- Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
- }
- protected final UserDetails retrieveUser(String username,
- UsernamePasswordAuthenticationToken authentication)
- throws UsernameNotFoundException {
- UserDetails loadedUser;
- try {
- loadedUser = this.getUserDetailsService().loadUserByUsername(username);
- }
- catch (UsernameNotFoundException notFound) {
- // if (authentication.getCredentials() != null) {
- // String presentedPassword = authentication.getCredentials().toString();
- // passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
- // presentedPassword, null);
- // }
- throw notFound;
- }
- catch (Exception repositoryProblem) {
- throw new InternalAuthenticationServiceException(
- repositoryProblem.getMessage(), repositoryProblem);
- }
- if (loadedUser == null) {
- throw new InternalAuthenticationServiceException(
- "UserDetailsService returned null, which is an interface contract violation");
- }
- return loadedUser;
- }
- /**
- * Sets the PasswordEncoder instance to be used to encode and validate passwords. If
- * not set, the password will be compared as plain text.
- * <p>
- * For systems which are already using salted password which are encoded with a
- * previous release, the encoder should be of type
- * {@code org.springframework.security.authentication.encoding.PasswordEncoder}.
- * Otherwise, the recommended approach is to use
- * {@code org.springframework.security.crypto.password.PasswordEncoder}.
- *
- * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder}
- * types.
- */
- public void setPasswordEncoder(Object passwordEncoder) {
- Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
- if (passwordEncoder instanceof PasswordEncoder) {
- setPasswordEncoder((PasswordEncoder) passwordEncoder);
- return;
- }
- if (passwordEncoder instanceof org.springframework.security.crypto.password.PasswordEncoder) {
- final org.springframework.security.crypto.password.PasswordEncoder delegate = (org.springframework.security.crypto.password.PasswordEncoder) passwordEncoder;
- setPasswordEncoder(new PasswordEncoder() {
- public String encodePassword(String rawPass, Object salt) {
- checkSalt(salt);
- return delegate.encode(rawPass);
- }
- public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
- checkSalt(salt);
- return delegate.matches(rawPass, encPass);
- }
- private void checkSalt(Object salt) {
- Assert.isNull(salt,
- "Salt value must be null when used with crypto module PasswordEncoder");
- }
- });
- return;
- }
- throw new IllegalArgumentException(
- "passwordEncoder must be a PasswordEncoder instance");
- }
- private void setPasswordEncoder(PasswordEncoder passwordEncoder) {
- Assert.notNull(passwordEncoder, "passwordEncoder cannot be null");
- this.userNotFoundEncodedPassword = passwordEncoder.encodePassword(
- USER_NOT_FOUND_PASSWORD, null);
- this.passwordEncoder = passwordEncoder;
- }
- protected PasswordEncoder getPasswordEncoder() {
- return passwordEncoder;
- }
- /**
- * The source of salts to use when decoding passwords. <code>null</code> is a valid
- * value, meaning the <code>DaoAuthenticationProvider</code> will present
- * <code>null</code> to the relevant <code>PasswordEncoder</code>.
- * <p>
- * Instead, it is recommended that you use an encoder which uses a random salt and
- * combines it with the password field. This is the default approach taken in the
- * {@code org.springframework.security.crypto.password} package.
- *
- * @param saltSource to use when attempting to decode passwords via the
- * <code>PasswordEncoder</code>
- */
- public void setSaltSource(SaltSource saltSource) {
- this.saltSource = saltSource;
- }
- protected SaltSource getSaltSource() {
- return saltSource;
- }
- public void setUserDetailsService(UserDetailsService userDetailsService) {
- this.userDetailsService = userDetailsService;
- }
- @Override
- public boolean supports(Class<?> authentication) {
- return true;
- }
- protected UserDetailsService getUserDetailsService() {
- return userDetailsService;
- }
- }
|