Spring Security mapping uppercase in URL - spring

I work on a JEE project, using the Spring Boot framework.
For the authentification, I use Spring Security, and I specified the pages in my template.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/token", "/index", "/index.html", "/main", "/main.html", "/main2", "/main2.html", "/recent1", "/recent1.html", "/recent2", "/recent2.html").hasRole("USER");
http
.csrf()
.disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/index");
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
The issue is that when I run the application and I wrote the URL with uppercase letters like: localhost:8080/INDEX.HTML or I add two letters localhost/index.httml, the page does appear without authantification.

If I understand correctly, here is the desired logic:
/login does not need to be secured by Spring Security (no roles are required)
All the other pages have to be secured with "USER" role.
To implement this, you could try the following:
#Override
public void configure(WebSecurity web) throws Exception {
// configuring here URLs for which security filters
// will be disabled (this is equivalent to using
// security="none")
web
.ignoring()
.antMatchers(
"/login"
)
;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().hasRole("USER");
http.csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/index");
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
So item 1 (no security on /login) is moved to configure(WebSecurity), and item 2 is left in the original configure(HttpSecurity).

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 how to allow root url without intefering with security 'below' the root

I have REST services and static pages, both delivered by my Spring Boot application.
The application action is to be reached under /myapp, while under /myapp/api there are services that are protected by a filter.
The filter expects a cookie.
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.permitAll()
.and()
.addFilter(new CookieFilter(...));
}
The unprotected pages in the 'root-context (/myapp) have no cookie.
How can I configure that the static pages are 'ignored' by Spring security? While the REST endpoints below the static pages are checked by security?
When I try to configure the static pages for 'exclusion' via Web Security, all REST endpoints under /myapp/api are ignored as well
#Override
public void configure(final WebSecurity web) {
web.ignoring()
.antMatchers("/");
}
If I configure a permitAll():
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll();
http.authorizeRequests()
.antMatchers("/api/**")
.permitAll()
.and()
.addFilter(new CookieFilter(...));
}
Spring security complains that the static pages can not be checked by my security filter, so the authorization is performed.
This will make anything under /api require authentication and let everything else through.
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.addFilter(new CookieFilter(...));

How to make a custom UsernamePasswordAuthenticationFilter register at an endpoint other than /login?

I've been following a tutorial to implementing JWT authentication in Spring Boot but am trying to adapt it to a case where I have two WebSecurityConfigurerAdapter classes, one for my API (/api/** endpoints) and one for my web front-end (all other endpoints). In the tutorial, a JWTAuthenticationFilter is created as a subclass of UsernamePasswordAuthenticationFilter and added to the chain. According to the author, this filter will automatically register itself with the "/login" endpoint, but I want it to point somewhere different, such as "/api/login" because I'm using this authentication method for my API only.
Here's the security configuration code for both the API and front-end (with some abbrevation):
#EnableWebSecurity
public class MultipleSecurityConfigurations {
#Configuration
#Order(1)
public static class APISecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
}
#Configuration
public static class FrontEndSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/?logout")
.and()
.authorizeRequests()
.mvcMatchers("/").permitAll()
.mvcMatchers("/home").authenticated()
.anyRequest().denyAll()
;
}
}
}
The question is: how can I define an endpoint such as "/api/login" as the endpoint for my custom JWTAuthenticationFilter?
Or, do I need to change the filter to not be a subclass of UsernamePasswordAuthenticationFilter and if so, how would I configure that?
EDIT: Something I've tried:
I guessed that the /api/login endpoint needed to be .permitAll() and I tried using formLogin().loginProcessingUrl(), even though it's not really a form login - it's a JSON login. This doesn't work. When i POST to /api/login I end up getting redirected to the HTML login form as if I were not logged in. Moreover, my Spring boot app throws a weird exception:
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"
The configuration I'm trying now:
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**")
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.formLogin().loginProcessingUrl("/api/login").and()
.authorizeRequests()
.antMatchers("/api/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()));
}
Since JWTAuthenticationFilter is a UsernamePasswordAuthenticationFilter, you could change the login endpoint directly on the filter instance:
JWTAuthenticationFilter customFilter = new JWTAuthenticationFilter(authenticationManager());
customFilter.setFilterProcessesUrl("/api/login");
http.addFilter(customFilter);
This configures JWTAuthenticationFilter to attempt to authenticate POST requests to /api/login.
If you wish also to change the default POST to another method (e.g. GET), you can set the RequiresAuthenticationRequestMatcher instead. For instance:
customFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/login", "GET"));

Spring Security. Any request needs to be authorized and a special POST request needs an admin role. How to do this?

I want to secure my HATEOAS REST API build with Spring. All requests should need authorization and POST requests to "/rooms" should need the admin role. My WebSecurityConfigurerAdapter implementation code looks like this right now:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// Todo: Make sure that all resources need to be authenticated and POST rooms needs ADMIN role
.anyRequest().authenticated()
.antMatchers(HttpMethod.POST, "/api/v1/rooms").hasRole("ADMIN")
.and()
.httpBasic()
.and()
.csrf().disable();
}
Right now all resources only need authentication if I put the "anyRequest().authenticated()" line before the "antMatchers..." line, but then the needed "ADMIN" role doesn't work or get applied and vice versa.
How am I to get both things working at the same time?
Kind Regards,
Florian
Securityconfiguration.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/public/**")
.permitAll().antMatchers("/sa/**").hasAuthority("sa")
.antMatchers("/admin/**").hasAuthority("admin")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/index.html").and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
.csrf().disable();
}
And in the rest controller use..
#RequestMapping("/admin/adduser")
public void addUser(#RequestBody User user) {
authService.addUser(user);
}
The following code did it for me:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/v1/rooms").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
Thank you for the response Pankaj.

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

Resources