diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java index 245e99053..fcfc0b6e5 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/core/PigxDaoAuthenticationProvider.java @@ -4,6 +4,8 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.util.WebUtils; +import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder; +import com.pig4cloud.pigx.common.security.service.PigxUser; import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService; import lombok.SneakyThrows; import org.springframework.core.Ordered; @@ -33,150 +35,151 @@ import java.util.Optional; */ public class PigxDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { - /** - * The plaintext password used to perform PasswordEncoder#matches(CharSequence, - * String)} on when the user is not found to avoid SEC-2056. - */ - private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword"; + /** + * The plaintext password used to perform PasswordEncoder#matches(CharSequence, + * String)} on when the user is not found to avoid SEC-2056. + */ + private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword"; - private final static BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter(); + private final static BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter(); - private PasswordEncoder passwordEncoder; + private PasswordEncoder passwordEncoder; - /** - * The password used to perform {@link PasswordEncoder#matches(CharSequence, String)} - * 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 volatile String userNotFoundEncodedPassword; + /** + * The password used to perform {@link PasswordEncoder#matches(CharSequence, String)} + * 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 volatile String userNotFoundEncodedPassword; - private UserDetailsService userDetailsService; + private UserDetailsService userDetailsService; - private UserDetailsPasswordService userDetailsPasswordService; + private UserDetailsPasswordService userDetailsPasswordService; - public PigxDaoAuthenticationProvider() { - setMessageSource(SpringUtil.getBean("securityMessageSource")); - setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()); - } + public PigxDaoAuthenticationProvider() { + setMessageSource(SpringUtil.getBean("securityMessageSource")); + setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder()); + } - @Override - protected void additionalAuthenticationChecks(UserDetails userDetails, - UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, + UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { - // app 模式不用校验密码 - String grantType = WebUtils.getRequest().getParameter(OAuth2ParameterNames.GRANT_TYPE); - if (StrUtil.equals(SecurityConstants.APP, grantType)) { - return; - } + // app 模式不用校验密码 + String grantType = WebUtils.getRequest().getParameter(OAuth2ParameterNames.GRANT_TYPE); + if (StrUtil.equals(SecurityConstants.APP, grantType)) { + return; + } - if (authentication.getCredentials() == null) { - this.logger.debug("Failed to authenticate since no credentials provided"); - throw new BadCredentialsException(this.messages - .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); - } - String presentedPassword = authentication.getCredentials().toString(); - if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { - this.logger.debug("Failed to authenticate since password does not match stored value"); - throw new BadCredentialsException(this.messages - .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); - } - } + if (authentication.getCredentials() == null) { + this.logger.debug("Failed to authenticate since no credentials provided"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + String presentedPassword = authentication.getCredentials().toString(); + if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { + this.logger.debug("Failed to authenticate since password does not match stored value"); + throw new BadCredentialsException(this.messages + .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + } - @SneakyThrows - @Override - protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) { - prepareTimingAttackProtection(); - String grantType = WebUtils.getRequest().getParameter(OAuth2ParameterNames.GRANT_TYPE); - String clientId = WebUtils.getRequest().getParameter(OAuth2ParameterNames.CLIENT_ID); + @SneakyThrows + @Override + protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) { + prepareTimingAttackProtection(); + String grantType = WebUtils.getRequest().getParameter(OAuth2ParameterNames.GRANT_TYPE); + String clientId = WebUtils.getRequest().getParameter(OAuth2ParameterNames.CLIENT_ID); - if (StrUtil.isBlank(clientId)) { - clientId = basicConvert.convert(WebUtils.getRequest()).getName(); - } + if (StrUtil.isBlank(clientId)) { + clientId = basicConvert.convert(WebUtils.getRequest()).getName(); + } - Map userDetailsServiceMap = SpringUtil - .getBeansOfType(PigxUserDetailsService.class); + Map userDetailsServiceMap = SpringUtil + .getBeansOfType(PigxUserDetailsService.class); - String finalClientId = clientId; - Optional optional = userDetailsServiceMap.values() - .stream() - .filter(service -> service.support(finalClientId, grantType)) - .max(Comparator.comparingInt(Ordered::getOrder)); + String finalClientId = clientId; + Optional optional = userDetailsServiceMap.values() + .stream() + .filter(service -> service.support(finalClientId, grantType)) + .max(Comparator.comparingInt(Ordered::getOrder)); - if (optional.isEmpty()) { - throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); - } + if (optional.isEmpty()) { + throw new InternalAuthenticationServiceException("UserDetailsService error , not register"); + } - try { - UserDetails loadedUser = optional.get().loadUserByUsername(username); - if (loadedUser == null) { - throw new InternalAuthenticationServiceException( - "UserDetailsService returned null, which is an interface contract violation"); - } - return loadedUser; - } - catch (UsernameNotFoundException ex) { - mitigateAgainstTimingAttack(authentication); - throw ex; - } - catch (Exception ex) { - throw ex; - } - } + try { + UserDetails loadedUser = optional.get().loadUserByUsername(username); + if (loadedUser == null) { + throw new InternalAuthenticationServiceException( + "UserDetailsService returned null, which is an interface contract violation"); + } else if (loadedUser instanceof PigxUser pigxUser) { + TenantContextHolder.setTenantId(pigxUser.getTenantId()); + } + return loadedUser; + } catch (UsernameNotFoundException ex) { + mitigateAgainstTimingAttack(authentication); + throw ex; + } catch (Exception ex) { + throw ex; + } + } - @Override - protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, - UserDetails user) { - boolean upgradeEncoding = this.userDetailsPasswordService != null - && this.passwordEncoder.upgradeEncoding(user.getPassword()); - if (upgradeEncoding) { - String presentedPassword = authentication.getCredentials().toString(); - String newPassword = this.passwordEncoder.encode(presentedPassword); - user = this.userDetailsPasswordService.updatePassword(user, newPassword); - } - return super.createSuccessAuthentication(principal, authentication, user); - } + @Override + protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, + UserDetails user) { + boolean upgradeEncoding = this.userDetailsPasswordService != null + && this.passwordEncoder.upgradeEncoding(user.getPassword()); + if (upgradeEncoding) { + String presentedPassword = authentication.getCredentials().toString(); + String newPassword = this.passwordEncoder.encode(presentedPassword); + user = this.userDetailsPasswordService.updatePassword(user, newPassword); + } + return super.createSuccessAuthentication(principal, authentication, user); + } - private void prepareTimingAttackProtection() { - if (this.userNotFoundEncodedPassword == null) { - this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD); - } - } + private void prepareTimingAttackProtection() { + if (this.userNotFoundEncodedPassword == null) { + this.userNotFoundEncodedPassword = this.passwordEncoder.encode(USER_NOT_FOUND_PASSWORD); + } + } - private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) { - if (authentication.getCredentials() != null) { - String presentedPassword = authentication.getCredentials().toString(); - this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword); - } - } + private void mitigateAgainstTimingAttack(UsernamePasswordAuthenticationToken authentication) { + if (authentication.getCredentials() != null) { + String presentedPassword = authentication.getCredentials().toString(); + this.passwordEncoder.matches(presentedPassword, this.userNotFoundEncodedPassword); + } + } - /** - * Sets the PasswordEncoder instance to be used to encode and validate passwords. If - * not set, the password will be compared using - * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()} - * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder} - * types. - */ - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - Assert.notNull(passwordEncoder, "passwordEncoder cannot be null"); - this.passwordEncoder = passwordEncoder; - this.userNotFoundEncodedPassword = null; - } + protected PasswordEncoder getPasswordEncoder() { + return this.passwordEncoder; + } - protected PasswordEncoder getPasswordEncoder() { - return this.passwordEncoder; - } + /** + * Sets the PasswordEncoder instance to be used to encode and validate passwords. If + * not set, the password will be compared using + * {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()} + * + * @param passwordEncoder must be an instance of one of the {@code PasswordEncoder} + * types. + */ + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + Assert.notNull(passwordEncoder, "passwordEncoder cannot be null"); + this.passwordEncoder = passwordEncoder; + this.userNotFoundEncodedPassword = null; + } - public void setUserDetailsService(UserDetailsService userDetailsService) { - this.userDetailsService = userDetailsService; - } + protected UserDetailsService getUserDetailsService() { + return this.userDetailsService; + } - protected UserDetailsService getUserDetailsService() { - return this.userDetailsService; - } + public void setUserDetailsService(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } - public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) { - this.userDetailsPasswordService = userDetailsPasswordService; - } + public void setUserDetailsPasswordService(UserDetailsPasswordService userDetailsPasswordService) { + this.userDetailsPasswordService = userDetailsPasswordService; + } }