Spring Security, to allow only users who have both roles to access the page - spring

First of all, I'm sorry I'm not good at English.
I created a class to extend WebSecurityConfigurerAdapter.
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().headers().frameOptions().disable()
.and()
.authorizeHttpRequests()
.antMatchers("/aaa/**", "/bbb/**").permitAll()
.antMatchers("/ccc", "/ddd/**").hasRole("AAA")
.antMatchers("/zzz/**").access("hasRole('AAA') and hasAnyRole('MASTER', 'ZZZ'")
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
// continue....
The situation I want is:
the user have both "AAA" and "MASTER" -> can access /zzz
the user have both "AAA" and "ZZZ" -> can access /zzz
Many sites I referenced say that I can apply roles with SpEL inside the "access" method.
However in the zzz line, the access method doesn't accept a String parameter.
Could you please tell me how to apply it?
Thanks.

Related

Spring Security filter chain with custom user ID check [duplicate]

This question already has answers here:
How to fix role in Spring Security?
(2 answers)
Closed 6 months ago.
I am trying to use an expression-based check for an user ID path variable, so users can only access resources that belong to them. It is pretty clearly described in the Spring documentation. But I cannot access the bean, with the error that a String is provided.
This is my security filter chain and the bean:
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.cors()
.and()
.csrf().disable()
.authorizeHttpRequests()
.antMatchers(WHITELIST_URLS).permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/api/**/users/{userId}/**").access("#userSecurity.checkUserId(authentication,#userId)")
.and()
.oauth2Login(oauth2login ->
oauth2login.loginPage("/oauth2/authorization/api-client-oidc"))
.oauth2Client(Customizer.withDefaults())
.build();
}
public static class UserSecurityConfig extends WebSecurityConfiguration {
#Bean("userSecurity")
private boolean checkUserId(Authentication authentication, String userId) {
return authentication.getPrincipal().equals(userId);
}
}
Error:
Required type: AuthorizationManager
<org.springframework.security.web.access.intercept.RequestAuthorizationContext>
Provided: String
I also have been trying to use an AuthorizationDecision (as lambda expression) but could not access the path variable.
Is the spring documentation wrong on this one? Been searching for quiet a while, but mostly found the same thing as in the Spring documentation.
Actually, I would like to manage this globally in the config and not on each mapping in the controllers by using the #PreAuthorize annotation.
Edit:
I have been unsuccessffuly trying to solve this using something like:
.access((authentication, object) ->
new AuthorizationDecision(object.getRequest().getServletPath().contains(
authentication.get().getName())))
or
.access((authentication, object) ->
new AuthorizationDecision(authentication.get().getPrincipal().equals(
object.getVariables().get("#userId"))))
I figured it out, the following example works. The more specific matcher has to be called first, otherwise it will not work.
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.cors()
.and()
.csrf()
.disable()
.authorizeHttpRequests()
.antMatchers("/api/v1/users/{userId}/**")
.access((authentication, object) -> new AuthorizationDecision(
object.getRequest().getServletPath().contains(
authentication.get().getName())
))
.antMatchers(WHITELIST_URLS)
.permitAll()
.antMatchers("/api/v1/**")
.authenticated()
.and()
.oauth2Login(oauth2login ->
oauth2login.loginPage("/oauth2/authorization/api-client-oidc"))
.oauth2Client(Customizer.withDefaults())
.build();
}

Springboot Security how to get role inside "Principal"

I have this fonts
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/**").hasRole("myRole")
.anyRequest().authenticated()
.and()
.oauth2Login(Customizer.withDefaults());
}
I know "hasRole" looks at permissions inside securityContext.authentication.authorities but is there a way for "hasRole" to another place?
My roles are inside securityContext.authentication.principal.attributes.role :
https://i.stack.imgur.com/yl6bC.png
I even created an endpoint that returns if the role I want exists, but I don't know how it would help me inside the "configure" method:
public boolean isAllowed() {
UserAttributesDTO user = getUser();
if (nonNull(user)) {
return user.getRoles().stream().anyMatch(role -> role.equals("admin_cadastro_externo"));
}
return false;
}
Since you're using the built-in oauth2Login() and your principal is a DefaultOidcUser, you want to use .hasAuthority("myAuthority") instead. You can influence what authorities are present by providing a GrantedAuthoritiesMapper as an #Bean.
If you must access the attributes in place, you may be interested in .access(...) using an #Bean reference.
See Referring to Beans in Web Security Expressions. In that case, you should use the authentication passed to the method instead of the SecurityContextHolder to access the authentication.

Spring HttpSecurity: Custom web security expressions

I am trying to configure the security of a new spring web application to check requests done against some of my urls.
Since none of the built-in expressions were valid for my logic, I decided to write my own, but it is not working at all.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**/actuator/**").permitAll()
.antMatchers("/**/instances/**").permitAll()
//Custom expresion to check against
.antMatchers("/(?!login|user-profiles)/**").access("#checkAccess.hasRoleSelected()")
.anyRequest().authenticated()
.and()
.httpBasic().disable()
.addFilterBefore(new JWTLoginFilter(jwtConfig.getUri(), authenticationManager(), tokenService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtTokenAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class);
}
#Service
public class CheckAccess {
public boolean hasRoleSelected() {
return true;
}
}
As you can see in the documentation, to get this done you need a bean with a method returning a boolean value. While I do have both, the method is never called and no error is thrown.
What am I missing?
Btw, I am running 5.2.2 version of spring security.
Your antMatcher is invalid.
.antMatchers("/(?!login|user-profiles)/**").
Have a look at the allowed patterns in the AntPathMatcher doc.
It is basically, "?", "*" and "**".
You might want to give the regexMatcher a try, instead.

Spring Security permitAll() for one URL under some pattern

I have /my-app/login url and I want to permitAll() for this URL. But this page under /my-app/** pattern which permit access only for registered user.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
How to do it?
Add .antMatchers("/my-app/login").permitAll() BEFORE .antMatchers("/my-app/**")... . The request matchers are stored in an list (ordered by the order in which they are defined), and Spring security will use the first rule thats matchers match to the current request. So put the most specific first and the common rules afterwards.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/login").permitAll()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
If my-app is the name of your application, and therefore the url that is by your application server (Tomcat) to map the url to the application, then you have to ommit it in the antMatcher because the antMatcher is configured "only" by the application relative url: /my-app/login become /login and /my-app/** become /**
add .anyRequest().permitAll() as last "matcher" of authorizeRequests()
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.anyRequest().permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
But to be honest: you use some kind of black listing (allow all URLs except some black listed) - and this is not the recommended way (from some security perspective). Because if you forget to add or misspell one URL that should been protected, then it is accessible for every body. The more secure way is to deny every url and allow only some (white list).

Spring Security 3 no-xml role restriction doesnt work

I'm using spring security in a new application and I configured the WebSecurityConfigurerAdapter. Everything with the filters works fine, but the problem comes on the distinction of two holes I have: Usuario(User) and Administrador(admin). The problem comes when I login with the User role and I access the path I restricted for that(/restricted) -- everything works fine, filter applyed --, but when I access as Admin, I can only manage to access the user path (/restricted), and not the /admin path, which I would like to.
Here bellow is the configuration as I did.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/includes/**", "/cadastrar", "/logout", "/login", "/", "/home").permitAll()
.antMatchers("/admin/**").hasRole("ADMINISTRADOR")
.anyRequest().authenticated().antMatchers("/restricted/**").hasRole("USUARIO")
.anyRequest().authenticated().and().formLogin()
.loginPage("/login").defaultSuccessUrl("/success-login", true)
.loginProcessingUrl("/login").failureUrl("/login?error=true").permitAll().and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/");
}
Does anybody here knows whats wrong?
Thanks much
Resolved. I've just changed to authority instead of hole. Everything works fine now.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasAuthority("ADMINISTRADOR")
.antMatchers("/restricted/**").hasAnyAuthority("USUARIO", "ADMINISTRADOR")
.antMatchers("/resources/**", "/includes/**", "/cadastrar", "/logout", "/login", "/", "/home").permitAll()
.and().formLogin()
.loginPage("/login").defaultSuccessUrl("/restricted/teste", true)
.loginProcessingUrl("/login").failureUrl("/login?error=true").permitAll().and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/");
}

Resources