401 unauthorized page for swagger? - spring-boot

I am enable swagger2 by #EnableSwagger2. However, when I try to hit "/swagger-ui.html", it first hit my Authentication Filter. Then, I wrote the following code to bypass the authentication check
String resourcePath = new UrlPathHelper().getPathWithinApplication(httpRequest);
if ("/swagger-ui.html".equalsIgnoreCase(resourcePath)) {
filterChain.doFilter(request, response);
}
I can see the filterChain.doFilter(request, response); was hit. However, when I let the debug go, it returns a page with information below
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Apr 04 15:41:50 EDT 2018
There was an unexpected error (type=Unauthorized, status=401).
No message available
Any idea, guys?

I encountered the same issue in my project and discovered this solution, so first add this config file to the project
package bla.bla.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configuration
#EnableSwagger2
public class Swagger2Config {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors
.basePackage("bla.bla.controllers"))
.paths(PathSelectors.any())
.build();
}
}
and then add this code block to you WebSecurityConfig
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs","/webjars/**");
}
my problem fixed
source : swagger.io

Think you can add your ownWebSecurityConfig extends WebSecurityConfigurerAdapter, than override configure(WebSecurity web) method and there put web.ignoring().antMatchers("/swagger-ui.html") ofc annotate that class with #Configuration

I have the same error and I add this code inside the class websecurityConfig
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll() // permit the class of test
.antMatchers("/**").permitAll() // permit all the routers after swagger-ui.html
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}

As answered by Georgi Stoyanov , adding that much code removed Whitelabel Error Page error but my swagger UI home page was blank as there was 401 issue in loading some css & js files.
Swagger-ui with Spring security
Also, important point that I want to mention is that my swagger UI was working for Weblogic deployment without above code (only HttpSecurity override was enough ) and I was facing issue only when running app in embedded tomcat.
Spring Boot Version : 1.5.2.RELEASE
SpringFox Version 2.8.0
So I had to made code changes as answered by me in linked question to load all CSS & JS files also.

I had the same problem and this was my solution.
if do you have a Spring security config, you must to give authorization at all urls that swagger needs
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/api/loggin").permitAll()
.antMatchers(HttpMethod.GET,"/swagger-resources/**").permitAll()
.antMatchers(HttpMethod.GET,"/swagger-ui/**").permitAll()
.antMatchers(HttpMethod.GET,"/v2/api-docs").permitAll()
.anyRequest()
.authenticated();
}
and in your class main you shuld to add this notation
#EnableSwagger2
and finally in yor pom.xml this dependencies.
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
for use http://localhost:8090/swagger-ui/

Related

How single authentication can work for multiple server nodes in Spring Security

I am using weblogic for deploying my spring boot application, and my same application is deployed on multiple nodes.
For example the two node in which the application is deployed is 9001 and 9002.
With basic security even if I am authenticated on the Node 9001 and trying to access the same URL on second node i.e on 9002, I am again getting redirected again to spring login page for authentication.
I want that once I authenticate using username and password on any node. I need not to authenticate again, Even if I am requesting to any other node.
Any kind of clue or help will be appreciated.
Thanks in advance.
The Security configuration file is
package com.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("test")
.password("{noop}test")
.authorities("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/userdetail").authenticated()
.anyRequest().permitAll()
.and()
.formLogin();
}
}
In my case it worked for both node when I enabled RedisHttpSession.
Below is the code which worked for me.
#Configuration
#EnableRedisHttpSession
public class RedisConfig {
#Bean
public JedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory();
}
}
also in pom.xml I needed to make two dependencies(For Spring boot).
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
You can also take reference about EnableRedisHttpSession from spring docs, and about spring session from
https://docs.spring.io/spring-session/docs/current/api/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSession.html
https://www.baeldung.com/spring-session

Spring Boot, Azure Active Directory, 404 Not Found Page

I am trying run azure active directory for my spring boot with web services. The problem is when I login successfully, it can not find a page that should be reachable.
I have added following properties (tetant-id, client-id, client-secret, user-group.allowed-group-names) with
azure.activedirectory.redirect-uri-template=login/oauth2/code
and my configuration is:
#Order(1)
#Configuration
#EnableWebSecurity
public class AADSecurityConfiguration extends AADWebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/health");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth2/**", "/login/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.defaultSuccessUrl("/list", true);
}
}
simple controller request is:
#GetMapping("/list")
#PreAuthorize("hasRole('Admin') or hasRole('Users')")
public String getListPage() {
return "list";
}
versions of the dependencies are:
<spring.security.version>5.6.0</spring.security.version>
<spring.boot.version>2.5.4</spring.boot.version>
<azure.version>3.10.0</azure.version>
I have already added redirects URIs like
as I mentioned when I login properly, /list page is not reachable, it shows 404 error below.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Nov 27 12:29:06 UTC 2021
There was an unexpected error (type=Not Found, status=404).
What could be a reason for that issue ?
Please check if below can be possible workarounds
In some cases,problem maybe the location of the Application startup class .Place the Application class on the outermost side,so that it contains all the subpackages.
Try to put application class ( which contain main method) at the root of controllers's package.(The purpose is to make the application contain all sub packages )
(or)
Error is due to Bootstrap class is not aware of the location of the controller where it needs to be looked.
Try adding in class level annotation in your main class: #ComponentScan(basePackages = {(name of your controller package)}
#ComponentScan(basePackages={"com.sample.controller"})
#SpringBootApplication
(Or)
Try adding thymeleaf dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Note: Also make sure ,if spring boot redirect url has to use the Azure
AD starter in this scenario, Set the redirect
URI to /login/oauth2/code/. For example:
http://localhost:8080/login/oauth2/code/. Be sure to include the
trailing /
Try to clear the cache and try again.
References:
spring-oauth-2-0-client-returns-401-unauthorized
spring-boot-SO

Principal is null in controller when using http.csrf().disable()

I have a controller and POJO that I want to test. The GET to the REST interface forces a login and returns a principal object and so all is good. I was able to extend WebSecurityConfigurerAdapter to enable and username and password for testing.
However, during testing, the Spring framework requires a CSRF token for a POST request. Since I have no UI and I am only testing the REST interface I want to disable it temporarily.
So I extended WebSecurityConfigurerAdapter as per the documentation:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
However this disabled the authentication. My controller receives a Principal object that is null. Here is my controller:
import java.security.Principal;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.neutech.model.ShoppingCart;
#Scope("session")
#RestController
#RequestMapping("/cart/api/v1")
public class SomeController {
#RequestMapping(value = "/thing", method = RequestMethod.POST)
public void create(#RequestBody String stuff,#AuthenticationPrincipal Principal user) {
// do stuff
}
I have tried various flavours of setting CSRF for specific URLs or HTTP verbs. All with the same result. The principal delivered to the controller is null.
After scouring the net for some kind of resolution to this I can come up with nothing. There are lots of examples tell me to do exactly what I am doing. However I only find only other similar type questions.
Can someone explain to me what I am doing wrong?
In order to enable authentication change your configure method, try this:
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.fullyAuthenticated();
If you use Spring Boot 1.5, you could disable CSRF by properties, see
Spring Boot Reference Guide:
security.enable-csrf=false # Enable Cross Site Request Forgery support.
If you use Spring Boot 2.0, you have to write a complete Spring Security configuration, see Spring Boot Security 2.0:
Custom Security
If you want to configure custom security for your application, you will need to add a WebSecurityConfigurerAdapter that adds all the bits that you want to configure. In order to avoid ordering issues with the WebSecurityConfigurerAdapter, Spring Boot auto-configuration will back off completely.
Example:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf().disable()
}
}

Add CSS file to Spring Boot + Spring Security Thymeleaf file

I wanted to add CSS file to my HTML file.
The problem appeared when I tried to add CSS to Spring Security application (I work on basic Spring Getting Started Content). I blame Spring Security because without it the CSS file loads properly.
Application.java file:
package mainpack;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
MvcConfig.java file:
package mainpack;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/register").setViewName("register");
registry.addViewController("/whatever").setViewName("whatever");
}
}
WebSecurityConfig.java file:
package mainpack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/index", "/register", "../static/css", "../static/images").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
I load CSS with line:
<link href="../static/css/index.css" th:href="#{/css/index.css}" rel="stylesheet" />
in index.html file.
Your pattern ../static/css is not matching your relative URL ../static/css/index.css, see AntPathMatcher:
PathMatcher implementation for Ant-style path patterns.
Part of this mapping code has been kindly borrowed from Apache Ant.
The mapping matches URLs using the following rules:
? matches one character
* matches zero or more characters
** matches zero or more directories in a path
{spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"
and Spring Boot Reference:
By default, resources are mapped on /** but you can tune that via spring.mvc.static-path-pattern.
Your request will be redirected to login form, because your are not logged in and all other requests need authentication.
To fix it, change your pattern to /css/** and /images/**.
A better solution for static resources is WebSecurity#ignoring:
Allows adding RequestMatcher instances that Spring Security should ignore. Web Security provided by Spring Security (including the SecurityContext) will not be available on HttpServletRequest that match. Typically the requests that are registered should be that of only static resources. For requests that are dynamic, consider mapping the request to allow all users instead.
Example Usage:
webSecurityBuilder.ignoring()
// ignore all URLs that start with /resources/ or /static/
.antMatchers("/resources/**", "/static/**");
The web.ignore()worked the best for me. just add the following method to your WebSecurityConfig class.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/img/**", "/icon/**");
}
.antMatchers("/**/*.js", "/**/*.css").permitAll();
This allows all the js and css files present in resources/static folder to be permitted for request access.

Spring Boot JS App wont work after securing rest-api with Spring Security

I created a simple Spring Boot/ JS App. In a next step I tried to implement an usermanagement feature to handle multiple users.
So I implemented a usermodel and controller and secured all rest-api calls via authentication of spring security.
#Configuration
#EnableWebSecurity
#ComponentScan("package.packagename")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception{
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select email, password, active from accounts where email=?")
.authoritiesByUsernameQuery("select email, role from account_roles where email=?");
}
#Override
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().permitAll()
.and()
.authorizeRequests()
.antMatchers("/index.html", "/").permitAll()
.anyRequest().authenticated()
.and()
.logout();
}
}
Additionally to this file I have the SecurityWebApplicationInitializer
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
My problem now is the fact, that if I start the application and try to access it via localhost:8080 I face an 404 Error.
Usually the app should work even without login and it seems that with springsecurity enabled the app is not able to load the js stuff in resources/public directory.
Reading the logs showed the following:
No mapping found for HTTP request with URI [/] in DispatcherServlet with name 'dispatcherServlet'
If I start the App without spring security it works without any problems.
The securing of the api-calls works like a charm - I'm able to login, receive a cookie and use this cookie to authenticate against the api-functions which are secured by springsecurity.
I hope you can help me to resolve my (hopefully small) problem.
Thanks in advance
When you use .formLogin() you need to define the login page or use .httpBasic() auth. So you can use something like this:
.formLogin()
.and()
.httpBasic();
or
.formLogin()
.loginPage("/login.html")
You can read more here
http://docs.spring.io/spring-security/site/docs/3.2.x/guides/form.html
http://www.baeldung.com/spring-security-login
I figured out that I have to add a WebConfig.java class like this:
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
#EnableWebMvc
#ComponentScan
public class WebConfig extends WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter {
}
Now Spring is able to resolve the / call properly. I just have to make sure to open the access to all files in public for all users (permitall() function).
Anyway thanks for your help :-)

Resources