Spring Boot security is not working in the simplest case - spring-boot

I have a very simple spring boot application to test out some security features. But I failed at the first step and I don't really understand why.
My application is a WebFlux application and has 2 users and 2 endpoints. One of the endpoint can be reached with user having "ADMIN" role, but for the other the user should only be authenticated. But I alway get HTTP 401 (Unauthorized) response.
Here is my 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 http://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>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-security</name>
<description>Demo project for Spring Boot Security</description>
<properties>
<java.version>11</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-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<release>11</release>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
These are my endpoints:
#Configuration
public class WebConfiguration {
Mono<ServerResponse> message(ServerRequest request) {
return ServerResponse.ok().body(Mono.just("Hello World!"), String.class);
}
Mono<ServerResponse> somethingElse(ServerRequest request) {
return ServerResponse.ok().body(Mono.just("Hello Else!"), String.class);
}
#Bean
RouterFunction<?> routes() {
return RouterFunctions.route().GET("/message", this::message)
.GET("/else", this::somethingElse)
.build();
}
}
And finally the security config:
#Configuration
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
ReactiveUserDetailsService userDetailsService() {
UserDetails user1 = User.withDefaultPasswordEncoder()
.username("notAdmin")
.password("notAdmin")
.roles("SYSTEM", "USER")
.build();
UserDetails user2 = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN", "USER")
.build();
return new MapReactiveUserDetailsService(user1,user2);
}
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/message")
.hasRole("ROLE_ADMIN")
.anyExchange()
.authenticated()
.and()
.build();
}
}
And this is how I call the service and what I get in response (pls note, the response is the same for both endpoints):
$ curl -v -uadmin:admin http://localhost:8080/else
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
* Server auth using Basic with user 'admin'
> GET /else HTTP/1.1
> Host: localhost:8080
> Authorization: Basic YWRtaW46YWRtaW4=
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm="Realm"
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
< Referrer-Policy: no-referrer
< content-length: 0
<
* Connection #0 to host localhost left intact
What am I doing wrong?

Update:
Just right after I clicked the submit button I found out what is the problem. An .httpBasic() is missing. Here is the correct security config:
#Configuration
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
ReactiveUserDetailsService userDetailsService() {
UserDetails user1 = User.withDefaultPasswordEncoder()
.username("notAdmin")
.password("notAdmin")
.roles("SYSTEM", "USER")
.build();
UserDetails user2 = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN", "USER")
.build();
return new MapReactiveUserDetailsService(user1,user2);
}
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/message")
.hasRole("ADMIN")
.anyExchange()
.authenticated()
.and()
.httpBasic()
.and()
.build();
}
}
Sorry, if I caused any inconvenience!

Related

Request from Angular to Spring Gateway fails CORS error

The project uses Spring-Security OAUTH 2. An Angular application is used as a web client. And as a Keycloak authorization server.
The Angular application sends requests to the Spring application via the Spring GateWay.
When I try to send a Get request, I get an error
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
file 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>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.amrut.prabhu</groupId>
<artifactId>spring-cloud-gateway-keycloak-oauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring Cloud Gateway Oauth2 With Keycloak</name>
<description>spring cloud gateway with keycloak oauth2</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
<lombok.version>1.18.22</lombok.version>
<logback-access-spring-boot-starter.version>3.1.2</logback-access-spring-boot-starter.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SecurityConfig
#Configuration
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, ServerLogoutSuccessHandler handler) {
http
.cors()
.and()
.csrf().disable()
.authorizeExchange()
.pathMatchers("/actuator/**", "/","/logout.html")
.permitAll()
.and()
.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.oauth2Login() // to redirect to oauth2 login page.
.and()
.logout()
.logoutSuccessHandler(handler)
;
return http.build();
}
#Bean
public ServerLogoutSuccessHandler keycloakLogoutSuccessHandler(ReactiveClientRegistrationRepository repository) {
OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
new OidcClientInitiatedServerLogoutSuccessHandler(repository);
oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}/logout.html");
return oidcLogoutSuccessHandler;
}
}
I tried to register in the Spring Gateway properties file, from this post
cors
spring:
cloud:
gateway:
default-filters:
- TokenRelay
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
I also tried to determine the global configuration of CORS, according to this article
baeldung.com
#Configuration
#EnableWebFlux
public class CorsGlobalConfiguration implements WebFluxConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("PUT")
.allowedMethods("GET")
.allowedHeaders("Baeldung-Allowed", "Baledung-Another-Allowed")
.exposedHeaders("Baeldung-Allowed", "Baeldung-Exposed")
.maxAge(3600);
}
}
I still get an error
What am I doing wrong?
I add all the necessary headers.
What else does he need?
And the #CrossOrigin annotation on the method always worked before.
The following two options also did not help solve the problem:
#Configuration
public class CorsWebFilterConfig {
#Bean
CorsWebFilter corsWebFilter() {
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
corsConfig.setMaxAge(8000L);
corsConfig.addAllowedMethod("PUT");
corsConfig.addAllowedMethod("GET");
// corsConfig.addAllowedHeader("Baeldung-Allowed");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", corsConfig);
return new CorsWebFilter(source);
}
}
OR
#Configuration
public class CorsWebFilterConfig implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange serverWebExchange,
WebFilterChain webFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
ServerHttpResponse response = serverWebExchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "http://localhost:4200");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "18000L");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();//HERE
}
return webFilterChain.filter(serverWebExchange);
}
}
The annotation on the method does not work either
#CrossOrigin(origins = "http://localhost:4200")
Here are the contents of the network tab, the first request is OPTIONS, the second is GET
Request URL: http://10.151.68.8:8484/auth/realms/demo/protocol/openid-connect/auth?response_type=code&client_id=spring-gateway-client&scope=message.write&state=dnAY-OwNUBGKuvZE5-3AH3L6v9W8OA5V67bD-U2YgiA%3D&redirect_uri=http://localhost:9090/login/oauth2/code/keycloak
Request Method: OPTIONS
Status Code: 200 OK
Remote Address: 10.151.68.8:8484
Referrer Policy: no-referrer
Response
Connection: keep-alive
Content-Length: 25
Content-Type: application/json
Date: Wed, 16 Nov 2022 07:34:59 GMT
Referrer-Policy: no-referrer
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Request
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
Host: 10.151.68.8:8484
Origin: null
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
For some reason, the Origin = null field in the request
Perhaps this is the reason for cors?
It turns out that Gateway sends a verification request to the authorization server with Origin = null and receives a cors error.
My hints are:
check what are the headers of your requests/responses in your browser
the gateway cors config could contain these as well:
cors()
.configurationSource(corsConfigurationSource()).and()...
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// other settings of configuration
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Maybe you checked the following link, but if not then worth a try in case the code above did not help: https://reflectoring.io/spring-cors/
The problem turned out to be that as a result of double forwarding of requests, the origin field became null. And when Keycloak received such a request, it threw a cors error. I found a temporary solution to this problem (thanks to the user #ch4mp):
I disable oauth2 on the gateway
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency> -->
in the properties file I write
spring:
cloud:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-methods: "*"
allowed-headers: "*"
exposed-headers: "*"
and I add two beans
#Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder, Function<GatewayFilterSpec, UriSpec> brutalCorsFilters) {
return builder
.routes()
.route(p -> p.path("/users/**").filters(brutalCorsFilters).uri("https://localhost:9443"))
.route(p -> p.path("/greet/**").filters(brutalCorsFilters).uri("https://localhost:9445"))
.build();
}
#Bean
Function<GatewayFilterSpec, UriSpec> brutalCorsFilters() {
return f -> f
.setResponseHeader("Access-Control-Allow-Origin", "*")
.setResponseHeader("Access-Control-Allow-Methods", "*")
.setResponseHeader("Access-Control-Expose-Headers", "*");
}
The solution is temporary, but I haven't found another one. And what offers baeldung.com it doesn't work.

SpringBoot OAuth2 Client Google RequestMapping not working in RestController

I am trying to build a SpringBoot OAuth2 Application but stuck with initiating the next POST request of access_token.
This is my code https://github.com/sangeeta-p-shetty/springboot_oauth2_google.git
It runs on http://localhost:8080/security. Currently it successfully redirects to Google and on Sign In redirects to the Redirect URL
Primarily, I am stuck at 3 areas:
#RequestMapping in #RestController is not working.
As RequestMapping is not working, the sample code even though successfully authorizes I am not able to initiate the next POST request of AccessToken. Wanted guidance on how to capture the response from Google and initiate a new request.
I wanted to redirect to OAuth2 only if specific URL is hit in the application. Currently Redirection is happening by launch of context. i.e http://localhost:8080/security
SecurityConfig.java
package com.google.config;
import ....;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// only disable these during testing or for non-browser clients
.cors().disable()
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/oauth2/authorization/google")
.authorizationEndpoint()
.authorizationRequestResolver(
new CustomAuthorizationRequestResolver(
clientRegistrationRepository(), "/oauth2/authorization"));
}
}
application.yml
server:
port: 8080
servlet:
context-path: /security
spring:
security:
oauth2:
client:
registration:
google:
client-id: test.apps.googleusercontent.com
client-secret: test
redirect-uri: http://localhost:8080/security/welcome.html
authorize-uri: https://accounts.google.com/o/oauth2/v2/auth
scope: email
response-type: code
cookie-path-domain: /
cookie-secure: true
provider:
google:
issuer-uri: https://accounts.google.com
SpringBootApplication class
package com.google;
#SpringBootApplication
#ComponentScan("com.google")
public class OidcExampleApp {
public static void main(String[] args) {
SpringApplication.run(OidcExampleApp.class, args);
}
}
AppController.java
Currently in the github code, this class is not included. But below is the intended code which does not seem to get called.
package com.google.controller;
import ...;
#RestController
public class AppController {
#RequestMapping(value="/welcome") // here even If I give value="/welcome.html") it does not work
public String getHi() {
System.out.println("End Point hit*************************************");
return "Hi";
}
}
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codetinkering</groupId>
<artifactId>spring-boot-oauth2-oidc-google</artifactId>
<version>1.0-SNAPSHOT</version>
<name>oauth2-example</name>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.13</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<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>
</dependencies>
<build>
<finalName>security</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.google.OidcExampleApp</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Logs Screenshot

Spring - oauth 2 - Cannot convert access token to JSON

I am trying to validate an access token on a resource server.
jwt.io validates the access token with the signature, so I guess the problem is spring configuration
This is my 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>uy.edu.anep</groupId>
<artifactId>aplicacion-funcionarios-service</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>aplicacion-funcionarios-service</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<start-class>edu.anep.familia.aplicacionfuncionarios.Application</start-class>
<org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<oauth-autoconfig.version>2.1.11.RELEASE</oauth-autoconfig.version>
<spring-cloud.version>Greenwich.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- oauth -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- https://stackoverflow.com/a/43574427/1989579 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>edu.anep.microservicios</groupId>
<artifactId>spring-DMZ-Utils</artifactId>
<version>0.0.8-spring_2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>recreate-docker</id>
<configuration>
<environmentVariables>
<COMPOSE_PATH>./</COMPOSE_PATH>
<COMPOSE_SERVICE_NAME>aplicacion-funcionarios-service</COMPOSE_SERVICE_NAME>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</environmentVariables>
<executable>rebuild.sh</executable>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
this my application.yml
server:
port: 8080
endpoints:
shutdown:
enabled: true
restart:
enabled: true
server.servlet.context-path: /aplicacion-funcionarios-service
security:
basic:
enabled: false
oauth2:
resource:
jwt:
key-value: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVSBre7DgM7FS1d9gzwBMaOY6j40AjcFHq3s9zx/0QMGAmRrVD2Eiuc7YdIZu9gRpCAohKDz1v0wmeE9Nafqw9XjcxJX2Te4+TTF8/Pia8adSyKVjpFMvlvCu83fdT+vgM3P08QLHtm19ToImTsI5oNZhH/iZNm8bjMJL4D4DXv3rOKwhKp5Sb2Hn8Qwes8MJSFO2YtVtqLCc60L2ERxPd5vZ/7s4mEIhI1bw/U/n5n5yPVHpXsZoP3Eru2LksDsWoWK/jKjJIhRtEZxbDuycMYEYiCaVaxLJ2Bwu41bob+FrS3YOlSqzQDpyTcpuACOdUmRFmtnRtORF1wnlDiyYQIDAQAB
-----END PUBLIC KEY-----
spring:
cloud.circuit.breaker.enabled: false
application:
name: aplicacion-funcionarios-service
#el formato en que van las fechas por defecto, sin zona horaria
jackson:
date-format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
time-zone: America/Montevideo
# Spring JDBC configuration
datasource:
url: ...
username: ...
password: ..
# Spring Data JPA configuration
jpa:
properties:
org.hibernate.envers.audit_table_suffix: _aud
org.hibernate.envers.default_schema: audit
hibernate:
#format_sql: true
#do_not_audit_optimistic_locking_field: false
dialect: org.hibernate.dialect.PostgreSQLDialect
#https://github.com/spring-projects/spring-boot/issues/12007#issuecomment-369388646
jdbc.lob.non_contextual_creation: true
hibernate:
# To be updated in real production usage! update create-drop none
#ddl-auto: update
show-sql: false
sleuth:
baggage-keys:
- x-request-id
- x-b3-traceid
- x-b3-spanid
- x-b3-parentspanid
- x-b3-sampled
- x-b3-flags
- x-ot-span-context
#configuracion del cache de redis
cache:
type: none
#Disable Ribbon
ribbon.eureka.enabled: false
#se habilita liquidbase
spring.liquibase.change-log: classpath:db/changelog/db.changelog-master.xml
logging.level.root: INFO
logging.level.org.springframework.web: DEBUG
logging.level.org.springframework.security: DEBUG
logging.level.org.springframework.security.oauth2: DEBUG
#logging.level.org.apache: trace
this is my config class
#Configuration
#EnableResourceServer
public class OAuth2SecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
//.antMatchers("/**").authenticated()
.antMatchers(
"/*/v2/api-docs",
"/v2/api-docs",
"/swagger-ui.html",
"/swagger-ui.html/**",
"/webjars/springfox-swagger-ui/**",
"/swagger-resources/**",
"/actuator/*"
).permitAll()
.anyRequest().authenticated();
//http.cors(
// #formatter:on
}
}
but I receive the following error in response
401
{
"error": "invalid_token",
"error_description": "Cannot convert access token to JSON"
}
the log shows little information
aplicacion-funcionarios-service_1 | 2019-12-14 22:31:57.545 DEBUG [aplicacion-funcionarios-service,2e8a7fbc810ad58c,2e8a7fbc810ad58c,false] 1 --- [nio-8080-exec-1] p.a.OAuth2AuthenticationProcessingFilter : Authentication request failed: error="invalid_token", error_description="Cannot convert access token to JSON"
aplicacion-funcionarios-service_1 | 2019-12-14 22:31:57.594 DEBUG [aplicacion-funcionarios-service,2e8a7fbc810ad58c,2e8a7fbc810ad58c,false] 1 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#64c00153
aplicacion-funcionarios-service_1 | 2019-12-14 22:31:57.598 DEBUG [aplicacion-funcionarios-service,2e8a7fbc810ad58c,2e8a7fbc810ad58c,false] 1 --- [nio-8080-exec-1] s.s.o.p.e.DefaultOAuth2ExceptionRenderer : Written [error="invalid_token", error_description="Cannot convert access token to JSON"] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#5739b1cb]
aplicacion-funcionarios-service_1 | 2019-12-14 22:31:57.599 DEBUG [aplicacion-funcionarios-service,2e8a7fbc810ad58c,2e8a7fbc810ad58c,false] 1 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
this is the header sent
Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsIm9yZy5hcGVyZW8uY2FzLnNlcnZpY2VzLlJlZ2lzdGVyZWRTZXJ2aWNlIjoiMSJ9.eyJzdWIiOiJkZW1vZG9jZW50ZSIsInJvbGVzIjpbXSwiaXNzIjoiaHR0cHM6XC9cL3ByZXByb2QuYW5lcC5lZHUudXlcL2NhcyIsIm5vbmNlIjpbIiJdLCJjbGllbnRfaWQiOlsiQVBQRnVuY2lvbmFyaW9zIl0sImF1ZCI6Imh0dHA6XC9cL2xvY2FsaG9zdDo4MDgxXC9cL2xvZ2luIiwiZ3JhbnRfdHlwZSI6WyJBVVRIT1JJWkFUSU9OX0NPREUiXSwicGVybWlzc2lvbnMiOltdLCJzY29wZSI6WyJlbWFpbCIsIm9wZW5pZCIsInByb2ZpbGUiXSwiY2xhaW1zIjpbXSwic2NvcGVzIjpbIm9wZW5pZCBwcm9maWxlIGVtYWlsIl0sInN0YXRlIjpbIiJdLCJleHAiOjE1NzYzOTE0MTgsImlhdCI6MTU3NjM2MjYxOCwianRpIjoiQVQtNS05a3ZvNGhsUFY0TUkzcjdReEticGRaSDYtMnRlNTQtdiJ9.NvFRFpa8XqYwGCYNHV6brBoi2wMsHH9YthbUK4wjifg7Kfeu__R9wialAyCUJViifi1cTCkTNfysbo-tH5WaJN3vrENDVSpSPlBbWJS5fVmNR45-HCDtLJkNsoexeTwNin1R5tz-GHNTnh4rNFjGJwj_gI5_MCFRYODBiuU_19HsVX_eEYJn7mPchk_Q8wujk9e_akPRLHzruCa3yilR6LGOzWWecQwVt3q0ZMgaOt-aG42OVuGySD-vgzpfJfPc4SFzYXyQYtvnuOyb3q1pxECzBVbW296uzzWaEOfV5OlGcMk_i4vN61HBQDMYbYcheehO3T7jZgCulYlGzit6Mw
I couldn't solve this using the spring-oauth dependencies.
I used
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
I created my custom filter that validate the token
public class JwtFilter extends GenericFilterBean {
private ObjectMapper mapper = new ObjectMapper();
private JWTVerifier verifier;
public JwtFilter(String key) throws Exception {
String publicKeyPEM = key
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey publicKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
Algorithm algorithm = Algorithm.RSA512(publicKey, null);
this.verifier = JWT.require(algorithm)
.build();
}
#Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = getAuthentication((HttpServletRequest) request);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
// Método para validar el token enviado por el cliente
private Authentication getAuthentication(HttpServletRequest request) {
try {
// Obtenemos el token que viene en el encabezado de la peticion
String tokenStr = request.getHeader("Authorization");
tokenStr = tokenStr.replace("Bearer", "").trim();
//se verifica la firma del token
DecodedJWT jwt = verifier.verify(tokenStr);
String token = newString((Base64.getDecoder().decode(jwt.getPayload())), "UTF-8");
//verifica si el token expiro
Date today = new Date();
if (jwt.getExpiresAt() != null && (today.compareTo(jwt.getExpiresAt()) > 0)) {
return null;
}
//AHORA VA A CARGAR LOS ROLES EN VASE AL USUARIO
CustomPrincipal userDetail = new CustomPrincipal();
userDetail.setRoles(new LinkedList());
...
List<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(
userDetail.getRoles()
.stream().toArray(size -> new String[size])
);
return new UsernamePasswordAuthenticationToken(userDetail, null, roles);
} catch (Throwable t) {
//t.printStackTrace();
}
return null;
}
public static String newString(final byte[] bytes, final String charsetName) {
if (bytes == null) {
return null;
}
try {
return new String(bytes, charsetName);
} catch (final UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
and then configure the filter like this
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#ConfigurationProperties(prefix = "security.custom")
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
private String publicKey = "...";
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
//.csrf().disable()
.cors().and()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED));
http
.authorizeRequests()
//.antMatchers("/**").authenticated()
.antMatchers(
"/*/v2/api-docs",
"/v2/api-docs",
"/swagger-ui.html",
"/swagger-ui.html/**",
"/webjars/springfox-swagger-ui/**",
"/swagger-resources/**",
"/actuator/*"
).permitAll()
.anyRequest().authenticated()
.and()
// Las demás peticiones pasarán por este filtro para validar el token
.addFilterBefore(new JwtFilter(publicKey), UsernamePasswordAuthenticationFilter.class);
//http.cors(
// #formatter:on
}
By default, Oauth2 Spring integration uses its own "type of tokens", if you want to work with JWT ones you have to specify how to deal with them developing the suitable behaviour of JwtAccessTokenConverter.
I hope the following links help you to solve the problem:
Option1
Option2
In the following link you will be able to see a tutorial with a complete integration with: JWT + Oauth2
On the other hand, in the next one you will find a fully functional microservice used as Oauth 2.0 security server integrated with Spring, that includes several other customizations:
Oauth 2 security server

Websockets on Spring boot website hosted on Azure returns Error 503/403

I have built a webapp on Spring Boot using Spring Security with Azure AD authentication and Websockets to communicate with clients. Locally this works perfectly but when i deploy it as an Azure Web App the Websocket connection fails with Error 503 and 403.
I've tried searching both here and Google for answers. Some of the answers point to an App setting where you can toggle websocket support in the web app on Azure but that setting is not there anymore. A lot of solutions i found are about 5 years old and not much relevant to my situation.
I'll share some code but it's pretty basic and mostly fetched from the guides online from Microsoft and Spring.
Jacascript that connect to the websocket endpoint:
stompClient = Stomp.over(socket);
stompClient.connect({}, onConnected, onError);
My websocketconfiguration:
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
Websecurity configuration:
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(oidcUserService);
http.headers().frameOptions().disable();
}
}
pom.xml
<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 http://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>2.1.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.groupId</groupId>
<artifactId>artifactId</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Name</name>
<description>This is a description</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.5.4</version>
<configuration>
<deploymentType>jar</deploymentType>
<!-- configure app to run on port 80, required by App Service -->
<appSettings>
<property>
<name>JAVA_OPTS</name>
<value>-Dserver.port=80</value>
</property>
</appSettings>
<!-- Web App information -->
<resourceGroup>myResourceGroup</resourceGroup>
<appName>myAppName</appName>
<region>myRegion</region>
<pricingTier>S1</pricingTier>
<!-- Java Runtime Stack for Web App on Linux -->
<linuxRuntime>jre8</linuxRuntime>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-spring-boot-bom</artifactId>
<version>2.1.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
I expect the websocket to connect as it does locally but i get this 503 error message reply:
Content-Length: 260
Content-Type: text/html
ETag: "5ce7bd82-104"
Server: nginx
Date: Fri, 31 May 2019 07:59:58 GMT
Followed by these:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
Expires: 0
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Date: Fri, 31 May 2019 07:59:59 GMT
Edit:
If i go to the requested url directly i get an error saying Can "Upgrade" only to "WebSocket".
Edit2:
If i tail my web app logs in the Azure client this message pops up:
0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 975], outboundChannel[pool
size = 0, active threads = 0, queued tasks = 0, completed tasks = 325], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 53124]```
It sounds like you might be running a web app container if the web socket setting is not visible.
 
To enable the WebSocket please run the below cmdlet for your site and let us know your results.
 
az webapp config set --web-sockets-enabled true --name <sitename> --resource-group <resourcegroupname>
Revisiting this after a couple of months. We hosted the app on another service and tried to deploy yet again to Azure just for kicks, and websockets worked.
I have not done any changes to the app or in azure.

HttpSecurity file do not have method oauth2Login()

I am doing Spring Security Oauth2. In client side I override
configure(HttpSecurity http) method and want to use oauth2Login()
method in HttpSecurity file. But HttpSecurity do not have this
function. I already add dependency of spring-security-oauth2-client,
spring-boot-starter-security and spring-security-oauth2 in pom.xml.
In HttpSecurity file it writes "Copyright 2002-2016 the original
author or authors". How can i update this?
#EnableWebSecurity
public class OauthConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
}
}
Please make sure your spring-boot-starter-parent version is correct.
The below is a sample:
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>your-artifactId</artifactId>
<version>your-version</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>
<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.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<!--if you need to generate token-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
How to configure WebSecurityConfigurerAdapter class:
1.with default implementations:
#Configuration
public class SimpleTestSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
with customized implementation for loginPage, authorizationEndpoint , TokenEndpoint, redirectionEndpoint, userInfoEndpoint:
#Configuration
public class SimpleTestSecurityConfig extends WebSecurityConfigurerAdapter {
private String[] PERMIT_ALL = {"unsecured-endpoint1", "unsecured-endpoint2", "..."};
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(PERMIT_ALL).permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.loginPage("/login")
.defaultSuccessUrl("/home")
.failureUrl("/error")
.authorizationEndpoint()
.baseUri("/oauth2/authorize-client") //default is "/oauth2/authorization"
.and()
.tokenEndpoint()
.accessTokenResponseClient(accessTokenResponseClient())
.and()
//.redirectionEndpoint()
//.baseUri("/oauth2/redirect") //base for google is "/login/oauth2/code"
//.and()
.userInfoEndpoint().oidcUserService(new OidcUserService(){
#Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
return super.loadUser(userRequest);
}
});
}
#Bean
public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository(){
return new HttpSessionOAuth2AuthorizationRequestRepository();
}
#Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient(){
return new NimbusAuthorizationCodeTokenResponseClient();
}
}
application.yml :
spring:
security:
oauth2:
client:
registration:
google:
client-id: your-client-id
client-secret: your-client-secret
redirectUriTemplate: "http://localhost:8080/login/oauth2/code/google"
scope:
- email
- profile
Since you are using spring boot you can use the following dependencies to auto configure the spring security for oauth2:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
After adding the above dependency if you want to override anything.The Spring Boot 2.x auto-configuration class for OAuth Client support is OAuth2ClientAutoConfiguration.
It performs the following tasks:
Registers a ClientRegistrationRepository #Bean composed of
ClientRegistration(s) from the configured OAuth Client properties.
Provides a WebSecurityConfigurerAdapter #Configuration and enables
OAuth 2.0 Login through httpSecurity.oauth2Login().
If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways:
Register a ClientRegistrationRepository #Bean
Provide a WebSecurityConfigurerAdapter
Completely Override the Auto-configuration
By overrriding WebSecurityConfigurerAdapter is as follows:
#EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientService(this.authorizedClientService())
.loginPage("/login")
.authorizationEndpoint()
.baseUri(this.authorizationRequestBaseUri())
.authorizationRequestRepository(this.authorizationRequestRepository())
.and()
.redirectionEndpoint()
.baseUri(this.authorizationResponseBaseUri())
.and()
.tokenEndpoint()
.accessTokenResponseClient(this.accessTokenResponseClient())
.and()
.userInfoEndpoint()
.userAuthoritiesMapper(this.userAuthoritiesMapper())
.userService(this.oauth2UserService())
.oidcUserService(this.oidcUserService())
.customUserType(GitHubOAuth2User.class, "github");
}
}
For reference see this :
https://docs.spring.io/spring-security/site/docs/5.0.7.RELEASE/reference/html/oauth2login-advanced.html
and
https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html

Resources