Issue
In my case I have an OAuth2 login with a CustomAuthenticationProvider. Now I have the problem that the CustomAuthenticationProvider is not called and I don't know why.
The login works so far without problems.
My properties that I have set for the client registration:
# CLIENT FOR AUTHORIZATION CODE GRANT #
spring.security.oauth2.client.registration.login-client.client-id=client-id
spring.security.oauth2.client.registration.login-client.client-secret=secret
spring.security.oauth2.client.registration.login-client.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.login-client.scope=openid, profile, roles
spring.security.oauth2.client.registration.login-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.login-client.redirect-uri=redirect-uri
spring.security.oauth2.client.provider.login-client.issuer-uri=issuer-uri
My SecurityConfig:
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
@Value("${keycloak.logout.uri}")
private String logoutUri;
@Autowired
private KeycloakAuthenticationProvider authProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(authProvider);
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
// Required for zkoss-uploads
http.headers()
.frameOptions()
.disable();
// Required for zkoss-logins
http.csrf().disable();
// Authorization on request
http.authorizeRequests()
.antMatchers("/actuator/**")
.permitAll()
.anyRequest()
.authenticated();
// OAuth2 Client
http.oauth2Client();
// OAuth2 Login
http.oauth2Login();
// Logout handling
http.logout().logoutSuccessUrl(logoutUri);
}
}
And my CustomAuthenticationProvider:
@Component
public class KeycloakAuthenticationProvider implements AuthenticationProvider
{
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
System.out.println("authenticate");
return authentication;
}
@Override
public boolean supports(Class<?> authentication)
{
System.out.println("support");
return true;
}
}
Note: My CustomAuthenticationProvider has no logic yet because I wanted to see if it is called first.
EDIT:
My dependencies:
<!-- Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<version>5.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.6.1</version>
</dependency>
Solution
I have now solved my problem myself.
The problem was that the configuration of http.oauth2Login()
provides its own AuthenticationProvider
and this is not overwritten with the AuthenticationManagerBuilder
.
My solution was to add a successHandler
to the oauth2Login
.
This has the task to rework and set the existing authentication that is created by the auto-config.
Here is my code:
@Autowired
private KeycloakAuthenticationSuccessHandler successHandler;
http.oauth2Login().successHandler(successHandler);
and my successHandler:
@Component
public class KeycloakAuthenticationSuccessHandler implements AuthenticationSuccessHandler
{
@Value("${logging.groupId}")
private String location;
private RequestCache requestCache = new HttpSessionRequestCache();
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException
{
var persistedAuth = (OAuth2AuthenticationToken) authentication;
var user = new DefaultOAuth2User(persistedAuth.getAuthorities(), persistedAuth.getPrincipal().getAttributes(), "name");
/*
* Sets new OAuth2AuthenticationToken with mapped authorities
*/
SecurityContextHolder.getContext()
.setAuthentication(new OAuth2AuthenticationToken(user, mapAuthorities(persistedAuth.getPrincipal().getAttributes()), persistedAuth
.getAuthorizedClientRegistrationId()));
/*
* Redirecting to the index page of website
*/
var redirectUri = requestCache.getRequest(request, response).getRedirectUrl();
redirectStrategy.sendRedirect(request, response, redirectUri);
}
@SuppressWarnings("unchecked")
private Collection<? extends GrantedAuthority> mapAuthorities(Map<String, Object> attributes)
{
var resourceRoles = new ArrayList<>();
var resourceAccess = (Map<String, List<String>>) attributes.get("resource_access");
if (resourceAccess.containsKey(location))
{
resourceRoles.addAll(((Map<String, List<String>>) resourceAccess.get(location)).get("roles"));
}
return resourceRoles.isEmpty() ? emptySet() : resourceRoles.stream().map(r -> new SimpleGrantedAuthority(valueOf(r))).collect(toSet());
}
}
Btw: Thanks to Marcus, through the tip with the debugger I found the solution!
Answered By - npriebe
Answer Checked By - Cary Denson (JavaFixing Admin)