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();
}
Related
I was searching a lot to find solution of my problem but nothing helps.
I am tryng to set up my Spring Security as:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/shapes").hasAnyAuthority("USER")
.antMatchers(HttpMethod.PUT, "/shapes").hasAnyAuthority("USER")
.antMatchers(HttpMethod.GET, "/shapes").permitAll()
.antMatchers("/users", "/shapes/history").permitAll()
.anyRequest().authenticated()
.and()
.cors()
.and()
.csrf()
.disable();
}
and now:
every request on endpoint /users is open, is not secured
#PostMapping("/shapes") is secured and returns 401 unauthorized
#GetMapping is secured too - it returns 401 error if I not add username and password <- there is problem of that question
/shapes/history is secured too
so the problem has to be here somewhere:
.antMatchers(HttpMethod.POST, "/shapes").hasAnyAuthority("USER")
.antMatchers(HttpMethod.PUT, "/shapes").hasAnyAuthority("USER")
.antMatchers(HttpMethod.GET, "/shapes").permitAll()
I won't to change endpoints, I would like to have #GetMapping and #PostMapping on the /shapes.
There are Authorization Server(UAA) and Resource Server and Gateway applications that have been working correctly. The scenario for authentication is authorization_code. In the first time after authentication, the end of request is added ;jesessionid=[value], so its result is exception from HttpFirewall of Gateway application, because of having ';' in the request.
My question is that what is it and why jessionid is added the end of request? and how is it adaptable with HttpFirewall.
I have found a way around but I know it has some risks. It is like this:
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirwall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
return firewall;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.headers().cacheControl().disable()
.and()
.headers()
.cacheControl()
.disable()
.frameOptions()
.sameOrigin()
.and()
.httpBasic().disable()
.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.mvcMatchers("/uaa/**", "/login**", "/favicon.ico", "/error**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.httpFirewall(allowUrlEncodedSlashHttpFirwall());
}
As above configuration, the ; is skipped but it is not right and it has some risks.
What is the correct way and config to solve this problem?
Before GET/POST request the client make a OPTIONS request, so I keep this calls ignored. But when I make this configuration, the another requests(GET/POST) are ignored too (but should not ignore).
When I add this line:
.antMatchers(HttpMethod.OPTIONS);
All requests are ignored, but the GET/POST should not ignored.
The following is the configuration method:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.POST, "/login")
.antMatchers(HttpMethod.OPTIONS);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers(HttpMethod.GET, "/login/authenticate").authenticated()
.antMatchers(HttpMethod.GET, "/credenciadas**").hasRole(PermissaoEnum.CONSULTAR_CREDENCIADA.getNomeInterno())
.antMatchers(HttpMethod.POST, "/credenciadas/validar").hasRole(PermissaoEnum.CONSULTAR_CREDENCIADA.getNomeInterno())
.antMatchers(HttpMethod.POST, "/credenciadas").hasRole(PermissaoEnum.INCLUIR_CREDENCIADA.getNomeInterno())
.antMatchers(HttpMethod.POST, "/credenciadas/alterar").hasRole(PermissaoEnum.ALTERAR_CREDENCIADA.getNomeInterno())
.antMatchers(HttpMethod.DELETE, "/credenciadas/").hasRole(PermissaoEnum.EXCLUIR_CREDENCIADA.getNomeInterno())
.and()
.addFilterBefore(authenticationByTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.csrf().disable();
}
Could you verify if you set the prefix string at role name as: "ROLE_"? The role name could be wrong.
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
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.