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
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.
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
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.
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?
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.