Spring 4 Restful Security - spring

I have just been experimenting with Spring 4 security. I am using the following method to map the secured endpoints:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/hello/*").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/hello/**").hasRole("ADMIN")
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
It occurred to me that if I had a lot of endpoints that the .antMatchers structure could become cumbersome.
Just curious to know if there is an alternative approach that may be more "manageable" - I guess this is a bit subjective?

I can suggest to have a method to just add the ant matchers. May be a Map for the path to role mapping and feed the map into that method to add the matchers.

Related

Spring security ant matcher's permitall doesn't work

As the title says Spring security's ant matcher's permit all doesn't work at all here's the method for it
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/css/*", "/js/*", "index").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/user/auth/register").permitAll()
.antMatchers("/get", "/delete/*", "/api/v1/user/auth/**").hasRole(ADMIN.name())
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
it should only allow the url ending with /get to be accessed by user that has admin role but I can access it without it (USER role) is there anything I'm doing wrong?
I tried changing the endpoint but didn't succeed at all

Spring Security and i18n

I have problem with accessing when I change language on page.
Without .antMatchers("/login*").permitAll() doesn't work but with /login* is almost ok but when I provide in URL 'http://localhost:8080/login?lang=estest123' or sth not related with i18n after login I receive ??language.change_estest123??.
I tried add .regexMatchers("^login\\?lang=[a-zA-Z]{2}|^login\\?lang=_{1}[a-zA-Z]{2}").permitAll() but same result as /login*.
Is any possible to accessing only for i18n ? in other case providing error? Or maybe another way of configuration for i18n which allows in easy way to provide this?
My web security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
Does the presence of parameters affect the url parsing for Security? Just use /login and it should pass /login and /login?lang=xxx.
But if you want to use direct mapping in your config you can use both of them: .antMatchers("/login", "/login*").permitAll()

antMatchers that matches any beginning of path

I've got REST service that will be used for authentication. The authentication endpoint will look like /api/v.1/authentication. The API version is a variable that can be changed to reflect updated versions. One example would be /api/v.2/authentication. I like to have an antMatcher that can deal with both these cases so I tried .antMatchers(HttpMethod.POST,"**/authenticate").permitAll() using ** to match any beginning of the endpoint but this doesn't work. The full setup below.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "**/authenticate").permitAll()
.antMatchers(HttpMethod.GET, "**/get-public-key").permitAll()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated();
}
Any suggestions how I can solve this?
You have to use absolute pattern, see AntPathMatcher:
Note: a pattern and a path must both be absolute or must both be relative in order for the two to match. Therefore it is recommended that users of this implementation to sanitize patterns in order to prefix them with "/" as it makes sense in the context in which they're used.
Your modified and simplified configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/**/authenticate").permitAll()
.antMatchers(HttpMethod.GET, "/**/get-public-key").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated();
}

Restrict access to Swagger UI

I have swagger UI working with spring-boot. I have a stateless authentication setup for my spring rest api which is restricted based on roles for every api path.
However, I am not sure how can i put <server_url>/swagger-ui.html behind Basic authentication.
UPDATE
I have following websecurity configured via WebSecurityConfig
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
One suggestion without knowing more about your configuration is from this SO question.
https://stackoverflow.com/a/24920752/1499549
With your updated question details here is an example of what you can add:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/sysadmin/**").hasRole("SYSADMIN")
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/siteadmin/**").hasRole("SITEADMIN")
.antMatchers("/api/**").hasRole("USER")
// add the specific swagger page to the security
.antMatchers("/swagger-ui.html").hasRole("USER")
.anyRequest().permitAll();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
The problem with this is it only protects the Swagger UI page and not the API specification which is loaded as a .json file from that UI page.
A better approach is to put the swagger files under a path so that you can just add antMatchers("/swagger/**").hasRole("USER")
A bit late to answer. I carried out a small POC to execute the same. I am using Keycloak and Spring Security. Below is my configuration
http
.antMatcher("/**").authorizeRequests()
.antMatchers("/swagger-resources/**","/swagger-ui.html**","/swagger-ui/").hasRole("admin")
.anyRequest().authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.defaultAuthenticationEntryPointFor(authenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
.and()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.clearAuthentication(true)
.addLogoutHandler(keycloakLogoutHandler());
I have a working example here

Mix HttpBasic and FormLogin in Spring Security with Spring-boot-starter

I use spring-boot-starter 0.5.0.M6 with spring security to build my application which contains:
"/admin/"**: should be accessible to anyone have role ADMIN, form-based login
"/api/"**: should be accessible to anyone have role API, http basic login
My first attempt was:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.defaultSuccessUrl("/admin/home")
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.permitAll();
http
.authorizeRequests()
.antMatchers("/api/**").hasRole("API")
.and()
.httpBasic();
}
With this approach:
all the "/admin/" and "/api/" can authentication use both basic & form-based login. This is not a critical issue.
when any security issue occurred, eg: authentication failed, or authorization failed, the login form is shown. This is a critical issue, I want if /api/** get authentication failed or authorization failed, it show the basic authentication popup with 401/403 status code.
Then I try with the solution from https://github.com/spring-projects/spring-security-javaconfig/blob/master/samples-web.md#sample-multi-http-web-configuration, but I only able to secure either /api/** or /admin/** but not both, depends on which one I annotated with #Order.
Please give me a hand.
Thanks much
For your api part, use the following. Note the first ant matcher that limits the scope of what is filtered by this security configuration. That was the part I did not understand at first from your reference.
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// the ant matcher is what limits the scope of this configuration.
http.antMatcher("/api/**").authorizeRequests()
.antMatchers("/api/**").authenticated()
.and().httpBasic().realmName("Sourcing API");
}
}

Resources