Add additional role to Keycloak authentication from outer source - spring-boot

I wanna authenticate users via Keycloak, but I need to add additional roles to Authentication object, that is using by Spring Security. Adding roles are saved in Postgres database.
I tried to override configureGlobal with custom AuthenticationProvider, but it didn't work.
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
ApplicationAuthenticationProvider provider = new ApplicationAuthenticationProvider();
provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(provider);
}
#Component
public class ApplicationAuthenticationProvider extends KeycloakAuthenticationProvider {
#Autowired
private UserService userService;
private GrantedAuthoritiesMapper grantedAuthoritiesMapper;
public void setGrantedAuthoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
this.grantedAuthoritiesMapper = grantedAuthoritiesMapper;
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
String username = ((KeycloakAuthenticationToken) authentication)
.getAccount().getKeycloakSecurityContext().getToken().getPreferredUsername();
List<Role> roles = userService.findRoles(username);
for (Role role : roles) {
grantedAuthorities.add(new KeycloakRole(role.toString()));
}
return new KeycloakAuthenticationToken(token.getAccount(), token.isInteractive(), mapAuthorities(grantedAuthorities));
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
private Collection<? extends GrantedAuthority> mapAuthorities(
Collection<? extends GrantedAuthority> authorities) {
return grantedAuthoritiesMapper != null
? grantedAuthoritiesMapper.mapAuthorities(authorities)
: authorities;
}
}
Tried to add additional filter, but i'm not sure in correct configuration.
#Bean
#Override
protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
RequestMatcher requestMatcher =
new OrRequestMatcher(
new AntPathRequestMatcher("/api/login"),
new QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN),
// We're providing our own authorization header matcher
new IgnoreKeycloakProcessingFilterRequestMatcher()
);
return new KeycloakAuthenticationProcessingFilter(authenticationManagerBean(), requestMatcher);
}
// Matches request with Authorization header which value doesn't start with "Basic " prefix
private class IgnoreKeycloakProcessingFilterRequestMatcher implements RequestMatcher {
IgnoreKeycloakProcessingFilterRequestMatcher() {
}
public boolean matches(HttpServletRequest request) {
String authorizationHeaderValue = request.getHeader("Authorization");
return authorizationHeaderValue != null && !authorizationHeaderValue.startsWith("Basic ");
}
}

Now I use Keycloak only for login/password. Roles and permissions now saved in local DB.

Related

Spring Security LDAP Authentication should authenticate only one user

I want my rest api to be restricted only for a particular user (SuperUser).
I am using Spring security the below code works fine if I give SuperUser/Password , it only checks for the correctness of the password.
Even if I give some random username with correct password it says authentication successful.
How to validate whether the user name given as part of BasicAuth is same as "SuperUser"
public class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${users-ldap.url}")
private String ldapUrl;
#Value("${users-ldap.username}")
private String userDn;
#Value("${users-ldap.password}")
private String password;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.ldapAuthentication()
.userDnPatterns("uid={0}")
.contextSource().url(ldapUrl)
.managerDn(userDn)
.managerPassword(getDrawPassword(password)).and()
.userSearchFilter("sAMAccountName=SuperUser");
}
#RequestMapping
public Authentication getAuth() {
return SecurityContextHolder.getContext().getAuthentication();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.antMatcher("/ws")
.httpBasic().and()
.authorizeRequests()
.anyRequest()
.authenticated().and()
.csrf().disable();
}
}
As per M .Denum suggestion using Custom Authentication provide I could solve the issue
` #Configuration
public class LdapAuthenticationProvider implements AuthenticationProvider {
#Value("${ldap.url}")
private String ldapUrl;
#Value("${ldap.username}")
private String userDn;
#Value("${ldap.password}")
private String password;
private LdapContextSource contextSource;
private LdapTemplate ldapTemplate;
private void initContext() {
contextSource = new LdapContextSource();
contextSource.setUrl(ldapUrl);
contextSource.setUserDn(userDn);
contextSource.setPassword(password);
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
initContext();
Filter filter = new EqualsFilter("sAMAccountName", authentication.getName());
Boolean authenticate = ldapTemplate.authenticate(LdapUtils.emptyLdapName(), filter.encode(),
authentication.getCredentials().toString());
if (authenticate && (authentication.getName().equalsIgnoreCase(Constants.SERVICE_ACCOUNT)
|| authentication.getName().equalsIgnoreCase(Constants.SERVICE_ACCOUNT_D))) {
UserDetails userDetails = new User(authentication.getName(), authentication.getCredentials().toString(),
new ArrayList<>());
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails,
authentication.getCredentials().toString(), new ArrayList<>());
return auth;
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
} `

Authenticate all APIs using Spring Security - HMAC based Custom Authentication

I am trying to implement HMAC Based authentication for all the REST API for my Microservice application (To know more about HMAC refer this). I have implemented below Spring security code but unable to get the app working with Spring security.
RESTSecurityConfig
#Configuration
#EnableWebSecurity
#Order(1)
public class RESTSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public RESTSecurityFilter authenticationFilter() throws Exception {
RESTSecurityFilter authenticationFilter = new RESTSecurityFilter("/");
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
#Bean
public RESTAuthenticationProvider authenticationProvider() {
RESTAuthenticationProvider provider = new RESTAuthenticationProvider();
return provider;
}
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().addFilterBefore(authenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
}
RESTSecurityFilter
public class RESTSecurityFilter extends AbstractAuthenticationProcessingFilter {
private static final Logger log = LoggerFactory.getLogger(RESTSecurityFilter.class);
private static final String ACCESS_KEY_PARAMETER_NAME = "x-access-key";
private static final String SIGNATURE_PARAMETER_NAME = "x-signature";
private static final String NONCE_PARAMETER_NAME = "x-nonce";
private static final String TIMESTAMP_PARAMETER_NAME = "x-timestamp";
private static final String SECRET_KEY = "xxxxxxxxxxxxxxxxx";
protected RESTSecurityFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String accessKey = getHeaderValue(request, ACCESS_KEY_PARAMETER_NAME);
String signature = getHeaderValue(request, SIGNATURE_PARAMETER_NAME);
String nonce = getHeaderValue(request, NONCE_PARAMETER_NAME);
String timestamp = getHeaderValue(request, TIMESTAMP_PARAMETER_NAME);
String message = accessKey + ":" + nonce + ":" + timestamp;
String hashSignature = null;
try {
hashSignature = HMacUtility.calculateHmac(message, SECRET_KEY);
log.info("hashSignature : {}", hashSignature);
}
catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
AbstractAuthenticationToken authRequest = createAuthenticationToken(accessKey,
new RESTCredentials(signature, hashSignature));
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}
private String getHeaderValue(HttpServletRequest request, String headerParameterName) {
return (request.getHeader(headerParameterName) != null) ? request.getHeader(headerParameterName) : "";
}
private AbstractAuthenticationToken createAuthenticationToken(String apiKeyValue, RESTCredentials restCredentials) {
return new RESTAuthenticationToken(apiKeyValue, restCredentials);
}
protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
#Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return true;
}
}
RESTAuthenticationProvider
public class RESTAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
private static final Logger log = LoggerFactory.getLogger(RESTAuthenticationProvider.class);
#Autowired
private UserSecurityService userSecurityService;
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
RESTAuthenticationToken token = (RESTAuthenticationToken) authentication;
if (token != null) {
if (authentication.getCredentials() == null) {
log.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage("badCredentials", "Bad credentials"));
}
RESTCredentials restCredentials = (RESTCredentials) authentication.getCredentials();
log.info("==========userDetails.getPassword() = {}", userDetails.getPassword());
log.info("=============restCredentials.getRequestSalt() = {}", restCredentials.getRequestSalt());
log.info("=============restCredentials.getSecureHash() = {}", restCredentials.getSecureHash());
// Check if signature and hashSignature matches and return API response
} else {
throw new AuthenticationCredentialsNotFoundException(
MessageFormat.format("Expected Authentication Token object of type {0}, but instead received {1}",
RESTAuthenticationToken.class.getSimpleName(), authentication.getClass().getSimpleName()));
}
}
#Override
protected UserDetails retrieveUser(String apiKey, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
log.info("Loading user by apikey = {}", apiKey);
UserDetails loadedUser;
try {
loadedUser = userSecurityService.getUserByApiKey(apiKey);
log.info("########### Loaded user = {}", loadedUser);
} catch (UsernameNotFoundException notFound) {
throw notFound;
}
if (loadedUser == null) {
throw new AuthenticationServiceException("UserSecurityServiceImpl returned null, which is an interface contract violation");
}
return loadedUser;
}
}
RESTAuthenticationToken
public class RESTAuthenticationToken extends UsernamePasswordAuthenticationToken {
private static final long serialVersionUID = 1L;
public RESTAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
public RESTAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
UserSecurityRepository
public interface UserSecurityRepository {
UserDetails getUserByUsername(String username);
UserDetails getUserByApiKey(String apiKey);
}
UserSecurityService
#Service
public interface UserSecurityService extends UserDetailsService {
UserDetails getUserByApiKey(String apiKey);
}
Is there a simple and efficient way to Authenticate API in filter without the provider? I have user sent "signature" and "hashSignature" both in filter so just want to compare them and return the API json response if both of them match.
Any help is very much appreciated! Thanks

Unable to implement Role based access to Spring-Boot API

I am new to Spring-Boot.I want to create an API which will have role based access with JWT token based authentication. But, unable to implement that.
I am not using JPA & Hibernate to fetch and map data. Instead I am using Ibatis.I have tried with #PreAuthorize and antMatchers & hasRole, but failed. By getting user id from JWT token, I am fetching details and roles and setting those to SecurityContextHolder.getContext().setAuthentication, still not working.
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("api/management/reports").hasRole("Supervisor");
}
Controller
#RestController
#RequestMapping("api")
#CrossOrigin
public class MyController {
#PreAuthorize("hasRole('Supervisor')")
#GetMapping("username")
public String reports(){
SecurityContext securityContext = SecurityContextHolder.getContext();
return securityContext.getAuthentication().getName();
}
}
AuthorizationFilter
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(JwtProperties.HEADER_STRING);
if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
Authentication authentication = getUsernamePasswordAuthentication(request,header);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
private Authentication getUsernamePasswordAuthentication(HttpServletRequest request, String header) {
try {
String token = header.replace(JwtProperties.TOKEN_PREFIX,"");
String userName = JWT.require(HMAC512(JwtProperties.SECRET.getBytes()))
.build()
.verify(token)
.getSubject();
List<User> searchedUserList = getUserDetailsDAO().getUserDetails(userName);
if (null !=searchedUserList && searchedUserList.size()>0) {
User searchedUser = new User();
searchedUser = searchedUserList.get(0);
List<RoleAccess> roleAccessList = new ArrayList<RoleAccess>();
XrefUsrRole oXrefUsrRole = new XrefUsrRole();
oXrefUsrRole.setUserName(searchedUser.getUsername());
roleAccessList = getRoleAccessDAO().getAccessDetails(oXrefUsrRole);
List<GrantedAuthority> authorities = uildUserAuthority(roleAccessList);
org.springframework.security.core.userdetails.User newUser = buildUserForAuthentication(searchedUser, authorities);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(newUser, null,authorities);
return auth;
}
return null;
}
return null;
} catch (IOException e) {
return null;
}
private org.springframework.security.core.userdetails.User buildUserForAuthentication(User searchedUser, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(searchedUser.getUsername(), searchedUser.getPassword(), true, true, true, true, authorities);
}
private List<GrantedAuthority> buildUserAuthority(List<RoleAccess> roleAccessList) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
// Build user's authorities
for (RoleAccess userRole : roleAccessList) {
setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
}
List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);
return Result;
}
In this case api/username should not accessible except users having Supervisor role.
You have ROLE_"+userRole.getModifiedBy()) which means you are granting roles with ROLE_NAME and in PreAuthorize you have Supervisor which is causing the issue. You can store role as ROLE_SUPERVISOR in a database then use it as below
// Build user's authorities
for (RoleAccess userRole : roleAccessList) {
setAuths.add(new SimpleGrantedAuthority("ROLE_"+userRole.getModifiedBy()));
}
use
#PreAuthorize("hasRole('ROLE_SUPERVISOR')")
.antMatchers("api/management/reports").hasRole("SUPERVISOR");

Successful Spring OAuth2 login with empty authorities

I implemented the login of my Spring Boot web app using OAuth2 and everything works fine.
The only problem is that the logged in user does not has the authorities information saved inside the session so each time I request a url and the controller has the annotation #PreAuthorize("hasRole('USER')") I get rejected.
SecurityConfiguration class:
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomOAuth2UserService customOAuth2UserService;
#Autowired
private CustomUserDetailsService userDetailsService;
#Autowired
private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.and()
.logout()
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.oauth2Login()
.loginPage("/login")
.failureUrl("/login?error=true")
.userInfoEndpoint()
.userService(customOAuth2UserService)
.and()
.failureHandler(oAuth2AuthenticationFailureHandler);
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
This is the CustomOAuth2UserService class:
#Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
#Autowired
private UserService userService;
#Override
public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest);
try {
return processOAuth2User(oAuth2UserRequest, oAuth2User);
}catch (Exception ex) {
// Throwing an instance of AuthenticationException will trigger the OAuth2AuthenticationFailureHandler
throw new InternalAuthenticationServiceException(ex.getMessage(), ex.getCause());
}
}
private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) {
OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(oAuth2UserRequest.getClientRegistration().getRegistrationId(), oAuth2User.getAttributes());
if(StringUtils.isEmpty(oAuth2UserInfo.getEmail())) {
throw new RuntimeException("Id not found from OAuth2 provider");
}
User user;
try {
user = userService.getByEmail(oAuth2UserInfo.getEmail());
if(!user.getProvider().toString().equalsIgnoreCase(oAuth2UserRequest.getClientRegistration().getRegistrationId())) throw new EmailAlreadyTakenException("email-already-taken");
} catch (UserNotFoundException e) {
user = registerNewUser(oAuth2UserRequest, oAuth2UserInfo);
}
return new CustomUserDetails(user);
}
private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
User user = new User();
user.setProvider(AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()));
Identity identity = new Identity(user);
if(oAuth2UserInfo.getFirstName() != null && !oAuth2UserInfo.getFirstName().equalsIgnoreCase(""))
identity.setFirstName(oAuth2UserInfo.getFirstName());
if(oAuth2UserInfo.getLastName() != null && !oAuth2UserInfo.getLastName().equalsIgnoreCase(""))
identity.setSecondName(oAuth2UserInfo.getLastName());
user.setIdentity(identity);
user.setEmail(oAuth2UserInfo.getEmail());
user.setConfirmedRegistration(true);
boolean flag = false;
String username = oAuth2UserInfo.getName().toLowerCase().replaceAll("\\s+", "");
user.setUsername(username);
return userService.addFacebookUser(user);
}
}
This a part of the application.properties file:
spring.security.oauth2.client.registration.facebook.client-id=***
spring.security.oauth2.client.registration.facebook.client-secret=***
spring.security.oauth2.client.registration.facebook.scope=email,public_profile
spring.security.oauth2.client.registration.google.client-id=***
spring.security.oauth2.client.registration.google.client-secret=***
spring.security.oauth2.client.registration.google.scope=email,profile
spring.security.oauth2.client.provider.facebook.authorizationUri = https://www.facebook.com/v3.0/dialog/oauth
spring.security.oauth2.client.provider.facebook.tokenUri = https://graph.facebook.com/v3.0/oauth/access_token
spring.security.oauth2.client.provider.facebook.userInfoUri = https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture
Once logged in the user can call this url /users/{username} but when he login with facebook or google through OAuth2, he gets rejected because the authorities list is empty. When he login with his webapp credential, the authorities list contains USER_ROLE and he is allowed to procede.
#PreAuthorize("hasRole('USER')")
#GetRequest("users/{username}")
public String getUser(#PathVariable String username, #PathVariable String subsection, Model model, Principal principal) throws IllegalAccessException, UserNotFoundException {
User user = userService.getByUsername(principal.getName());
model.addAttribute("user", user);
return "user";
}
Inside principal object there are:
When logged in with OAuth2:
principal: type CustomUserDetails (user information)
authorizedClientRegistrationId: type String ("google", "facebook")
authorities: type Collections$UnmodifiableRandomAccessList (empty)
details: null
authenticated: type boolean (true)
When logged in with local credentials:
principal: type CustomUserDetails (user information)
credentials: null
authorities: type Collections$UnmodifiableRandomAccessList
index:0 type SimpleGrantedAuthority ("USER_ROLE")
details: type WebAuthenticationDetails (remote address, sessionId)
authenticated: type boolean (true)
After some time of debugging I found the solution! I was not configuring correctly the roles of my user.
Inside the registerNewUser method of my custom OAuth2UserService I wasn't setting the Role of the User. I just added the line:
user.setRoles(new HashSet<>(Collections.singletonList(new Role("ROLE_USER"))));
and everything started to work! So now when the OAuth2User's authorities get asked, it just calls the getAuthorities of CustomUserDetails (my implementation of OAuth2User) and it calls the getRoles method of the User.
CustomUserDetails class:
public class CustomUserDetails extends User implements UserDetails, OAuth2User {
public CustomUserDetails() {
}
public CustomUserDetails(String username, String email, String password, Set<Role> roles) {
super(username, email, password, roles);
}
public CustomUserDetails(User user) {
super(user.getUsername(), user.getEmail(), user.getPassword(), user.getRoles());
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles()
.stream()
.map(role -> new SimpleGrantedAuthority(role.getRole()))
.collect(Collectors.toList());
}
#Override
public Map<String, Object> getAttributes() {
return null;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public String getName() {
return null;
}
}

AuthenticationProvider with passwordEncoder

When I try to use password encoder to check. It hasn't worked, I see "Bad password".
How should I receive authentication.getCredentials() to check passwords?
If I save user without encoding and try to log in, it works.
#Component
public class AuthClient implements AuthenticationProvider {
#Autowired
private ClientRepository clientRepository;
#Autowired
PasswordEncoder passwordEncoder;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String checkPassword = passwordEncoder.encode(authentication.getCredentials().toString());
Client client = this.clientRepository.findByUsername(username);
if (client == null) {
throw new UsernameNotFoundException("Invalid username/password");
}
String password = client.getPassword();
if (!password.equals(checkPassword)) {
throw new BadCredentialsException("Bad password");
}
Collection<? extends GrantedAuthority> authorities = translate();
return new UsernamePasswordAuthenticationToken(username,password,authorities);
}
private Collection<? extends GrantedAuthority> translate() {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_CLIENT"));
return authorities;
}
#Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication));
}
}
you are doing it wrong if you want to test two passwords you need to use passwordEncoder like this:
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, client.getPassword())) {
throw new BadCredentialsException("Bad password");
}

Resources