Setup custom 403 error page with Spring Boot 3 and Thymeleaf - spring-boot

I recently upgraded to spring boot 3 in an application with Thymeleaf, and my custom 403 pages are no longer working.
Prior to the upgrade, I believe this line was key:
http.exceptionHandling().defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), new AntPathRequestMatcher("/**"));
Since the upgrade, when I'm not authenticated and try to access a restricted page, I just get this default error screen. This my security filter chain.
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(requests -> requests
.requestMatchers("/",
"/login",
"/css/**",
"/js/**",
"/images/**",
"/static/favicon.ico",
"/favicon.ico",
"/fullscreen").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/logout-success")
.permitAll())
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), new AntPathRequestMatcher("/**"));
return http.build();
When logged in, my 404 and 500 error pages work as expected. I think there is something missing in the way I setup the security filter chain that is preventing this custom 403 error page from working. I couldn't find any resources on how to achieve this with spring boot 3. Any suggestions?

Thanks to the comments from #dur, the solution was to add spring.security.filter.dispatcher-types=request to my application.properties file.

Related

How Can I Customize Login Page for Oauth2 in Spring Webflux?

I just want to override default oauth2 login url (/login). How can I do that? The config I have tried without success:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange().pathMatchers(permittedUrls).permitAll()
.anyExchange().authenticated()
.and()
.oauth2Login(Customizer.withDefaults()).formLogin().loginPage("/oauth2_login")
.authenticationSuccessHandler(this::onAuthenticationSuccess)
.and()
.csrf().disable();
return http.build();
I was hoping it will redirect to /oauth2_login url but it didn't work. It still redirect to /login. But this time it returns 404 instead of showing default login page.
The code above is customizing the login page for formLogin which is typically username/password based log in from a form. It's much easier to see what configuration you are impacting using the new lambda style approach, so I have updated the entire configuration to use it. If you want to customize the login page for oauth2Login, then you should change the login page on it. For example:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers(permittedUrls).permitAll()
.anyExchange().authenticated()
)
.oauth2Login(oauth2 -> oauth2
// you now must render a log in page for the URL /login
.loginPage("/login")
);
// remove formLogin that was for a username/password based log in
// if you are doing oauth2 login I'm guessing you allow users to work within a browser, so you should not disable csrf
return http.build();
}

SpringBoot OAuth2 custom login page

I am able to integrate Zuul server or Spring Cloud gateway with Ping Open ID service.
The basic setup works well.
Now, due to the multi-tenant nature of our platform , I need to customize the default login page so I can provide branding capabilities .
I have tried to override the default OAuth2 login page by overriding the WebSecurityConfigurerAdapter as follows :
.authorizeRequests()
.antMatchers("/login").permitAll().and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login(oauth2 -> oauth2.loginPage("/login")) ;
and on the Cloud Gateway ( using Webflux ) as follows
#Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.oauth2Login(withDefaults()).exceptionHandling().authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/login")).and()
.build();
None of these methods work .
The "/login" is a GetMapping controller that attempts to render a simple HTML page with user and password fields.
Any help is appreciated.
thanks

How to access swagger endpoints securely?

I have added swagger ui in my application, earlier below two url's i was able to access directly without any authentication.
http://localhost:1510/swagger-ui.html
http://localhost:1510/v2/api-docs
i need secure swagger urls, don't want anybody directly see the api details of my application.
Note :- For authentication purpose i am using JWT with spring security in my application.
SO in order to secure swagger URLS , i have made entry in spring seurity config .. below code
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/userLogin").permitAll()
.antMatchers("/v2/api-docs").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/swagger-ui.html").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.apply(securityConfigurerAdapter());
}
and when i am trying to access swagger urls , i am getting below exception on browser and as well as on eclipse console.
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
How can i pass the jwt token to see the swagger page ?

Spring Boot, Spring Security specify redirect login url

At my Spring Boot application I need to implement a following scenario:
Anonymous User visits the following page: http://example.com/product-a.html
This User wants to ask a question about this product. It can be done at another page, located by the following address: http://example.com/product-a/ask. User press Ask Question button at the http://example.com/product-a.html and login/registration popup is shown. After successful login User should be automatically redirected to http://example.com/product-a/ask (but currently with a default Spring Security implementation User are redirecting back to the page originator http://example.com/product-a.html)
How to properly with Spring Boot/Spring Security implement/configure this redirect ?
UPDATED
This is my web security config:
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http
.csrf().ignoringAntMatchers("/v1.0/**", "/logout")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
//Anyone can access the urls
.antMatchers("/images/**").permitAll()
.antMatchers("/signin/**").permitAll()
.antMatchers("/v1.0/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority(Permission.READ_ACTUATOR_DATA)
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl(logoutSuccessUrl)
.permitAll();
// #formatter:on
}
I use OAuth2/JWT + Implicit Flow for AngularJS client
I think you should not use spring's default /login processing url, but create your own e.g /mylogin in a controller. And then you can inject the HttpServletRequest in the method and take the action based on the context of the request for example:
#PostMapping("/mylogin")
public ResponseEntity<> processingLogingURL(HttpServletRequest request){
// switch bases on the request URL after checking security off course
switch(request.getRequestURL()){
//redirect based on the caller URL
}
}
and finally change your .loginProcessingUrl("/login") to .loginProcessingUrl("/mylogin")

Spring security - Getting 404 error for REST call

I have an application that I am securing using Spring Security. I enable it using the annotations:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
I then configure it by overriding the configure() method:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.and()
.addFilterAfter(new CsrfCookieGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.accessDeniedHandler(new CustomAccessDeniedHandler())
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.loginProcessingUrl("/api/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.deleteCookies("JSESSIONID", "CSRF-TOKEN")
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/admin/**").hasAuthority(AuthoritiesConstants.ADMIN);
}
I'm getting redirected correctly to the login page when I try to get to the home page, but once I enter my credentials and try to login, I get the 404 not found error for /api/authentication REST call.
The loginProcessingUrl() method specifies the call to make. I don't have to implement this myself do I, as Spring should do that for me? Is there anything else I'm missing?
As far as I understood the login-processing-url, you have to handle the login process by yourself if you specify a special url to process the login.
Have you tried to just remove this line?:
.loginProcessingUrl("/api/authentication")
As you use springs default login form, you should just be able to remove the line and the generated login form will also change.
Maybe there's another way to solve your problem but this should also work.
If you're looking for an example on how to use custom login forms, this link might helo you.
I figured it out, it was a couple of things I needed to change:
I didn't have an Initializer class. After I added the following class, I went from a 404 not found error, to a 403 error:
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Note: you can also add the corresponding filter in your web.xml (read more here: http://websystique.com/spring-security/spring-security-4-hello-world-annotation-xml-example/)
The above change registers security with the Spring container. But I still needed to disable CSRF, as I wasn't sending the proper tokens from the client side. For my application, I don't need CSRF just yet so I have disabled it for now. However, this is not recommended so make sure sure you know what you are doing before making this change:
http.csrf().disable()

Resources