Spring security can't extract roles from JWT - spring-boot

im using FusionAuth for my Oauth server and I have a problem. Spring security will decode the JWT successfully but there are no roles!
This is my complete Authentication Object in JSON:
https://jsoneditoronline.org/#left=cloud.911cb58e717544ab9168632ed221aae1
and as you can see I have the roles and the role object in my principal. but when I try to use it in #PreAuthroize or even log it. it's empty.
WebSecurityConfigurerAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers(HttpMethod.GET, "v1/balance/**").permitAll()
.antMatchers(HttpMethod.POST, "v1/balance/**").permitAll()
.antMatchers(HttpMethod.GET, "/actuator/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer
.jwt(jwt ->
jwt.decoder(JwtDecoders.fromIssuerLocation(issuerUri)).jwkSetUri(jwksUrl)
)
);
}
this is how i try to log the roles:
#GetMapping("/currency/{currency}")
// #PreAuthorize("hasAnyRole('admin')")
public CurrencyBalance getWalletByCurrency(#PathVariable String currency, Principal principal){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Set<String> roles = authentication.getAuthorities().stream()
.map(r -> r.getAuthority()).collect(Collectors.toSet());
System.out.println(roles);
System.out.println(new Gson().toJson(authentication));
System.out.println(authentication.getAuthorities());
System.out.println(authentication.getCredentials().toString());
System.out.println(authentication.getDetails());
System.out.println(authentication.getPrincipal());
System.out.println(authentication.getName());
return null;
// return balanceService.getWalletByCurrency(principal.getName(),currency);
}

First of all, you need to understand How JWT Authentication Works
(source: spring.io)
JwtAuthenticationConverter converts JWT to authorities of Authentication, By default it only decode the SCOPE of JWT to authorities.(look at JwtGrantedAuthoritiesConverter).
You have to create a subclass of JwtAuthenticationConverter and override the extractAuthorities method if you want to decode custom attribute of JWT.
Finally, declare you custom subclass as a Bean, spring security will automatically use it

Related

How do i allow access certain request path to every user so that he/she can register user in spring security 6?

In spring security 5.7.5, I had the following security filter chain that allows unauthenticated users to easily register accounts.
Code in spring Security 5.7.5
#Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests(
authorize ->
authorize
.mvcMatchers("/user/**").permitAll()
.mvcMatchers("/**").authenticated()
).formLogin(Customizer.withDefaults());
return http.build();
But now, The previous way code is not working. How should I configure a filter chain that allows anyone to register accounts?
Present Code
#EnableWebSecurity
public class SecurityConfig {
#Bean
#Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());
//when unauthenticated user tries to login the resource server
// redirect him/her to login page
http
.exceptionHandling(
exception ->
exception.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login")
)
);
return http.build();
}
#Bean
#Order(2)
public SecurityFilterChain appSecurityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.disable()
.authorizeHttpRequests(
authorize ->
authorize
.requestMatchers("/user/registerUser",
"/user/getAllUser").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.build();
}
}
I'm getting 401 unauthorized in postman when i request for /user/registerUser and /user/getAllUser url. What i'm trying is, registering user account by unauthenticated users. I belive my security filter chain is sending me to /login page to authenticate which i don't want for register url.

SAML with Spring security anonymousUser

We have to implement SSO using SAML in SpringBoot. I have achieved to redirect the user to the identity provider login page and make the login. The problem is that after the login, when I try to get the user info with SecurityContextHolder.getContext().getAuthentication() I get anonymousUser, and not the logged user data.
Here is my SecurityConfig
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().and()
.authorizeRequests()
.antMatchers("/saml/**).permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.userDetailsService(samlUserDetailsServiceImpl)
.serviceProvider()
.protocol("http")
.hostname("localhost:8080")
.basePath("/")
.keyStore()
.storeFilePath("classpath:metadata/samlKeystore.jks")
.keyPassword(keystorePass)
.keyname(keystoreAlias)
.and()
.and()
.identityProvider()
.metadataFilePath("classpath:metadata/idp.xml")
.discoveryEnabled(false)
.and()
.and();
And the implementation of SAMLUserDetailService
#Service
public class SamlUserServiceImpl implements SAMLUserDetailsService {
#Override
public Object loadUserBySAML(SAMLCredential credential) {
String userID = credential.getNameID().getValue();
GrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_GESTOR");
return new User(userID, "DUMMY", Collections.singletonList(userAuthority));
}
I have debugged the code and in the SAMLUserDetailsService implementation I receive the user data after logging.
Also, is there a way to indicate the redirection url when the user has logged? Now it redirects to same url.
Thanks in advance

Spring security : configure JWT with formLogin

I am trying to configure JWT filter with formLogin authentication .
(My server serve UI clients (thats why i need formLogin ) and i am exposing also Rest End Point (to be authenticated by JWT ) .
currently my JWT is working , but it seems that my Roles (anyRole) -- isnt working .
here is my configure method :
post login -> if I am trying to reach /kuku path - I get 302 and login page again .
if i am removing the addFilterBefore -> my roles is working fine .
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/").hasRole("ADMIN")
.antMatchers("/kuku/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.formLogin().defaultSuccessUrl("/inital.html", true)
;
http.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
String userName = "Admin"; // currently due to Vault IMPL - this input is hardcoded .
String password ="Admin"
auth.inMemoryAuthentication()
.withUser(userName).password(passwordEncoder().encode(password))
.roles("ADMIN");
}
Try adding csrf().disable() to your configure(http) method. This worked in my case where I have similar configuration as yours. Although, I suggest searching for whether or not this is secure, because this disables built-in csrf protection.

Spring Webflux -Security: How to let Spring return 401 (UNAUTHORIZED) exception when jwt token expired or wrong

Below is code which authorise JWT token (Keyclock) but in case of exception , server never returns 401
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
// the matcher for all paths that need to be secured (require a logged-in user)
http.authorizeExchange(exchanges -> exchanges.pathMatchers("/actuator/**").permitAll()
.pathMatchers("/abcde/auth").permitAll()
.pathMatchers("/abcde/auth/refresh").permitAll()
.anyExchange().authenticated())
.csrf().disable()
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer
.jwt(withDefaults())
).exceptionHandling(exception-> exception.authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() ->
{
swe.getResponse()
.setStatusCode(HttpStatus.UNAUTHORIZED);
}
)
)
);
return http.build();
}
Another question :
Will this piece of code only validate expiry of JWT token or also other validation? What exactly happens is what i am interested to know.
In nutshell is this code sufficient enough for keyclock JWT validation through issuer URL?

How can I get roles or groups from Azure SAML 2.0 Application in Spring Boot

I have a spring boot application where I need to limit access for specific endpoints. So far I can authenticate against Azure using SAML 2.0.
This is the main configuration of the authentication in Spring
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(samlEntryPoint());
http
.csrf()
.disable();
http
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class);
http
.authorizeRequests()
.antMatchers("/error").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated();
http
.logout()
.logoutSuccessUrl("/");
}
in Azure I have added the roles to the claim values as shown in the image below
Azure Claims
My target is to be able evantaully to do something like the following:
#GetMapping("/")
#PreAuthorize("hasRole('User')")
public String getSample(Principal principal) {
log.info("Get Request");
return "Hello";
}
Next step would be to implement your own SAMLUserDetailsService that would return the corresponding UserDetail instance with the rights Authorities granted to the user.
You would have to retrieve the list of Azure role from the SAMLCredential (something like credential.getAtttributeAsString(<your_attribute_name>) then you would have to map theses values with the list of authorities defined in your application.

Resources