Spring Security 6 POST requests are unauthorised with permitAll() - spring

I am using Spring Boot 3, Spring Security 6. My Security configuration doesn't work properly. I have 2 paths on which any request should be permitted, and for everything else one needs to authenticate.
Both GET and POST method work on those that need authentication.
On those with permitAll(), only GET requests work. For POST, I get 401 Unauthorised.
I took care of CSRF, and anyway I expect all the POST requests to work, not only those with authentication.
On Postman, I selected POST, No Auth, put a RAW body and selected JSON. I really don't know why is it not working.
Here is my code:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http, KeycloakLogoutHandler keycloakLogoutHandler) throws Exception {
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
XorCsrfTokenRequestAttributeHandler delegate = new XorCsrfTokenRequestAttributeHandler();
// set the name of the attribute the CsrfToken will be populated on
delegate.setCsrfRequestAttributeName("_csrf");
// Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the
// default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler
CsrfTokenRequestHandler requestHandler = delegate::handle;
http
.authorizeHttpRequests().requestMatchers("/firstpath/**", "/secondpath/**", "/error/**").permitAll().and()
.authorizeHttpRequests().anyRequest().authenticated().and()
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
http.oauth2Login()
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler)
.logoutSuccessUrl("/");
http.csrf((csrf) -> csrf
.csrfTokenRepository(tokenRepository)
.csrfTokenRequestHandler(requestHandler));
return http.build();
}
}
#Slf4j
#RestController
#RequestMapping("/firstpath")
public class NameitController {
#PostMapping(value = "path", produces = WSConstants.JSON_MEDIATYPE)
#ResponseBody
public ResponseEntity saveMyObject(#RequestBody ObjectDTO dto) {
[...] //my code
}
}
I also tried http.authorizeHttpRequests().requestMatchers(HttpMethod.POST, "/firstpath/path").permitAll(), but at no use.
Edit: It still has to do with CSRF protection, because when I tired http.csrf().disable();, everything worked fine. But I still want CSRF protection, it seems like the token is not sent with permitAll()?...
Edit2: After adding Spring Security logs:

In your postman, I do not see X-XSRF-TOKEN header. If you’re not sending the XSRF-Token back to the server after fetching it from the cookie, you might wanna do it as shown in the end of the answer since it is one of the ways it is designed to protect against CSRF attacks and only works like that. In frameworks like angular, we can get it as a cookie from spring boot server and send it back as a header to differentiate malicious sites accessing the same URL, since such sites, inside the browser, cannot access the cookie associated with our genuine domain to send it back as a header.
Here is a simple working project which uses spring security 6 and crsf token with postman testing if it can help. It uses InMemoryUserDetailsManager, NoOpPasswordEncoder(Not recommended for production) and basic authentication.
SecurityConfig:
import java.util.function.Supplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
#Configuration
public class ProjectSecurityConfig {
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
XorCsrfTokenRequestAttributeHandler delegate = new XorCsrfTokenRequestAttributeHandler();
delegate.setCsrfRequestAttributeName("_csrf");
CsrfTokenRequestHandler requestHandler = new CsrfTokenRequestHandler() {
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
Supplier<CsrfToken> csrfToken) {
delegate.handle(request, response, csrfToken);
}
};
return http
.cors().disable() // disabled cors for simplicity in this example in case of testing through a ui
.authorizeHttpRequests()
.requestMatchers("/error").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRequestHandler(requestHandler)
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().formLogin()
.and().httpBasic()
.and().build();
}
#Bean
InMemoryUserDetailsManager userDetailsService() {
UserDetails admin = User.withUsername("admin").password("pass").authorities("admin").build();
return new InMemoryUserDetailsManager(admin);
}
#Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
Controller:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.learning.entity.DataObject;
#RestController
public class TestController {
#PostMapping("/post")
public String post(#RequestBody DataObject dataObject) {
return "succesfull post";
}
}
DataObject Model:
public class DataObject {
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
application.properties:
logging.level.org.springframework.security.web.csrf=TRACE
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.learning</groupId>
<artifactId>spring-security-3-csrf-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-3-csrf-example</name>
<description>spring learning</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Test using CSRF token in postman:
First add basic auth credentials-
Add data object json body-
Send a mock request to the server to get a XSRF Cookie
Use this Cookie value as a header with name "X-XSRF-TOKEN"-
Testing it-
Note:- Since version 6, Spring Security does not create sessions for basic authentication by default so no Cookie for session will be returned in this example.
UPDATE :-
Here is an article on a more sophisticated way to send XSRF-TOKEN through postman as pointed by #OctaviaAdler in the comments. TLDR in case the link goes down:- Create an environment in postman and add the variable "xsrf-token" in it. Inside the request, add the header X-XSRF-TOKEN with the value set to "{{xsrf-token}}" (name of the environment variable in double curly braces without quotes). Then add the following script inside the "Tests" tab -
var xsrfCookie = postman.getResponseCookie("XSRF-TOKEN");
postman.setEnvironmentVariable("xsrf-token", xsrfCookie.value);

THe order in which you define in security config please have a look order like this
`#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/auth/**")
.permitAll()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.anyRequest()
.authenticated()
.and()
.cors()
.and()
.exceptionHandling()
.authenticationEntryPoint(this.jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.disable();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}`

Related

spring boot rest app secured by keycloak 18 return always error 401 Unauthorized

I'm developing microservices some of them with spring boot web and other with spring boot data rest and I want secure them with keycloak server 18 through OpenId protocol. The microservices endpoint can be accessed from frontend adding in the "Authorization header" the bearer token obtained from post request to the url http://localhost:8280/auth/realms/--realm_name--/.well-known/openid-configuration inserting in the body request the key client_id, username, password, grant_type, client_secret.
I have create
1.a realm,
2.a client named "springboot-mc-dev" (with Access Type = confidential;,
"Root URL" and "Valid Redirect URIs" both setted to "http://localhost:8490",
"Standard Flow Enabled", "Direct Access Grants Enabled", "Service Accounts Enabled" and "Authorization Enabled" setted to "ON"),
3.before a role inside client ("named springboot-mc-dev-role" composite False) and after a role inside realm (named always "springboot-mc-dev-role" composite true that is associated Client Roles "springboot-mc-dev-role" of client springboot-mc-dev),
4.user mapped to role "springboot-mc-dev-role" in "realm roles"
After I have imported the following dependency in parent pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java-version>1.8</java-version>
<keycloak.version>18.0.2</keycloak.version>
</properties>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Here there is the code of SecurityConfig.java class
package it.organization.project.microservice.datamart.config.security;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
#KeycloakConfiguration
#Configuration
#EnableWebSecurity
#Import(KeycloakSpringBootConfigResolver.class)
#EnableGlobalMethodSecurity(jsr250Enabled = true)
#ConditionalOnProperty(name = "ms-security-enable", havingValue = "true")
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
grantedAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
//keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper);
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
/*protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}*/
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/**").hasRole("springboot-mc-dev-role")
//.anyRequest().hasRole("springboot-mc-dev-role")
//.anyRequest().//authenticated()
//permitAll()
;
http.csrf().disable();
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
//public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
this is the code of main class
package it.organization.project.microservice.datamart;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
#SpringBootApplication
#EnableCaching
public class MAINDataMartApplication {
public static void main(String[] args) {
Security.addProvider(new BouncyCastleProvider());
SpringApplication.run(MAINDataMartApplication.class, args);
}
}
and last there is the application.yml with keycloak settings
#KEYCLOAK CONFIGURATION
keycloak:
auth-server-url: http://localhost:8280/auth
#ssl-required: external
realm: realmname
bearer-only: true
#public-client: true
use-resource-role-mappings: true
resource: springboot-mc-dev
credentials:
secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
this is the result
What is wrong?
Keycloak spring adapter is deprecated. Don't use it.
Have look at those tutorials for alternatives.
We are missing important info to answer preecisely:
Spring versions?
reason for 401 (from Postman console, value of WWW-Authenticate response header)?
There can be few reasons for 401 Unauthorized:
missing authorization header
expired or not yet valid token (for instance because of timezone misconfiguration on either authorization or resource server)
different issuer in access-token claim and Spring config: host, port, etc must be exactly the same
Spring configured for a different type of authentication than what authorization server supports (i.e. opaque token with introspaction and one side and JWT on the other)
...
If you're using Keycloak 18 with Quarkus, it is likely that your conf should reference http://localhost:8280 as issuer (and not http://localhost:8280/auth).
So, look at Postman console, open your access-token with a tool like https://jwt.io and compare values you find there with what you have in spring conf and logs.

new Authorization Server Custom Login Page

I am using new Spring Authorization Server
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
I wan to configure custom login page. I have two beans configured
AuthorizationServerConfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http.cors(Customizer.withDefaults())
.formLogin()
.and().build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.authorizeRequests(authorizeRequests ->
authorizeRequests.mvcMatchers("/custom-login", "/css/**", "/js**", "/image/**").permitAll().anyRequest().authenticated()
)
.formLogin()
.loginPage("/custom-login").failureForwardUrl("/custom-login?error");
return http.build();
}
Whenever User enter incorrect credentials is not being directed to /custom-login?error
He is directed to /custom-login
I seems .failureForwardUrl("/custom-login?error"); is not working
If don't use custom login page user is being directed to /login?error=some-error
Can someone help to solve this problem?
I solved the problem.
I changed the configuration to
AuthorizationServerCOnfig.java
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
return http
.cors(Customizer.withDefaults())
.formLogin().loginPage("/custom-login").failureForwardUrl("/custom-login?error=true")
.and()
.build();
}
SecurityConfig.java
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.cors(withDefaults())
.formLogin().failureForwardUrl("/custom-login")
return http.build();
}
I added LoginController.java to handle custom-login redirects.
#Controller
public class LoginController {
#GetMapping("/custom-login")
public String login() {
return "login";
}
#PostMapping("/custom-login")
public String loginFailed() {
return "redirect:/authenticate?error=invalid username or password";
}
}
If you don't specify those end points. you will be redirected to /login
Also I had both
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.2.3</version>
</dependency>
My service was both authorization server and resource server at the same time.
So I removed
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
And every thing works expectedly

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 Keycloak Bearer only

Iam developing a angular webapp which is connected to a java (spring framework) backend. Authentication is done via a keycloak server.
On my local machine with the embedded tomcat server the angular application and the spring application runs without errors.
For deployment i need to use the old fashioned way by using an existing tomcat server.
The angular frontend is available in the ROOT directory via http://myurl/
The spring backend is placed as war file and reachable via http://myurl/api/
Everything works on the server except the authentication part.
Angular app is able to login via redirect etc. and gets an access token.
This token is transmitted on a request to the spring backend.
But the backend return a not authorized message.
Any help is apriciated!
Message is:
Unable to authenticate using the Authorization header
I have created a SecurityConfig class:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()
.permitAll();
}
}
Added this line to the application properties
keycloak
keycloak.auth-server-url=https://authserver.net/auth
keycloak.realm=myRealm keycloak.bearer-only=true
keycloak.resource=myclient
keycloak.cors=true
And added this dependancies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>3.3.0.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Disabling the csrf token solved this issue.
Example:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/*")
.authenticated()
.anyRequest()

401 unauthorized page for swagger?

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/

Resources