Spring Security + AAD: invalid_token_response follow-up with latest available spring-boot version (2.1.2) - spring-boot

I am facing the same issue as posted in the question Spring Security + AAD: invalid_token_response
I did try 2.1.0, it didn't help.
I am currently using Spring-boot 2.1.2, spring-security-oauth2-client 5.1.3 and i am still getting the same error
I am sharing 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.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>perdict</groupId>
<artifactId>ouath2-client</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<name>ouath2-client</name>
<build>
<finalName>predictouath2client</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<java.version>1.8</java.version>
<azure.version>2.1.2</azure.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>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security.oauth.boot/spring-security-oauth2-autoconfigure -->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-spring-boot-bom</artifactId>
<version>${azure.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
and the WebSecurityConfig looks like:-
#EnableWebSecurity
#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);
}
the application.yaml looks like:-
spring:
security:
oauth2:
client:
registration:
azure:
client-id: xxxxxxxxxxxxxxxx
client-secret: xxxxxxxxxxxxxxxx
client-authentication-method: basic
authorization-grant-type: authorization_code
redirect-uri-template: '{baseUrl}/login/oauth2/code/{registrationId}'
scope: openid, https://graph.microsoft.com/user.read
client-name: Microsoft Azure
client-alias: azure
provider:
azure:
authorization-uri: https://login.microsoftonline.com/xxxxxxxxxxxxxx/oauth2/authorize
token-uri: https://login.microsoftonline.com/xxxxxxxxxxxxxx/oauth2/token
user-info-uri: https://login.microsoftonline.com/xxxxxxxxxxxxxx/openid/userinfo
jwk-set-uri: https://login.microsoftonline.com/xxxxxxxxxxxxxx/discovery/keys
user-name-attribute: name
azure:
activedirectory:
tenant-id: xxxxxxxxxxxxxx
active-directory-groups: Users
The detail error from the log files is
2019-02-08 05:48:28.612 DEBUG 99981 --- [nio-8010-exec-4] o.s.web.client.RestTemplate : Response 401 UNAUTHORIZED
2019-02-08 05:48:28.619 DEBUG 99981 --- [nio-8010-exec-4] .s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.oauth2.core.OAuth2AuthenticationException
2019-02-08 05:48:28.620 DEBUG 99981 --- [nio-8010-exec-4] .s.o.c.w.OAuth2LoginAuthenticationFilter : Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized
at org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.authenticate(OidcAuthorizationCodeAuthenticationProvider.java:143) ~[spring-security-oauth2-client-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:186) ~[spring-security-oauth2-client-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]

Related

Unable to Access Spring Boot Actuator Endpoints

I try to use actuator endpoints in spring boot. The application runs smoothly. My pom file is given below:
<?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.3</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.luv2code.springboot</groupId>
<artifactId>thymeleafdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>thymeleafdemo</name>
<description>Ab Jove principium</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- umumi bağımlılıklar -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Here is the content of the application.properties file:
spring.datasource.url=DATABASE_URL
spring.datasource.username=USERNAME
spring.datasource.password=PASSWORD
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
# Spring Data JPA properties
spring.data.jpa.repository.packages=com.yok.springboot.thymeleafdemo.dao
spring.data.jpa.entity.packages-to-scan=com.yok.springboot.thymeleafdemo.entity
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.ddl-auto=create
#
# JDBC properties
#
app.datasource.jdbc-url=DATABASE_URL
app.datasource.username=USERNAME
app.datasource.password=PASSWORD
#
# Hikari properties
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.idleTimeout=2000
spring.datasource.hikari.poolName=SpringBootJPAHikariCP
spring.datasource.hikari.maxLifetime=20000
spring.datasource.hikari.connectionTimeout=30000
# Actuator properties
# expose all endpoints:
management.endpoints.web.exposure.include=*
management.endpoints.beans.enabled=true
management.endpoints.web.exposure.include=info,env
management.endpoint.env.enabled=true
management.endpoint.info.enabled=true
management.endpoints.enabled-by-default=true
This is the start of my Spring Boot Application:
package com.yok.springboot.thymeleafdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ThymeleafdemoApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeleafdemoApplication.class, args);
}
}
Whenever I try to connect /health,/Info or /metrics endpoint by typing http://localhost:8080/health, the HTTP request transfers to http://localhost:8080/showMyLoginPage. I cannot reach endpoint. How can I solve this? Thanks in advance.
Edit -1
Mr. Fatih demands me to observe the result "http://localhost:8080/actuator" and this picture reveals: the picture
Here is the console output of the application:
https://drive.google.com/file/d/1zYP1qe-Ohbcan93ZO6rqjxX9LqlGiIIg/view?usp=sharing
Edit-2
The problem is partly solved. The actuators are available after the login of the application. But the problem is, after the login page, the homepage appears. All actuators are working, however, whenever I hit http://localhost:8080/actuator/health URL, {"status":"DOWN"} appears at the screen. Here is the console output taken during this operation:
reached urls:
http://localhost:8080/showMyLoginPage
http://localhost:8080/students/list/page/1
http://localhost:8080/actuator/health
http://localhost:8080/actuator/heapdump
http://localhost:8080/actuator/env
console output: (exception has thrown)
java.lang.IllegalArgumentException: dataSource or dataSourceClassName
or jdbcUrl is required. at
com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1029)
~[HikariCP-4.0.3.jar:na] at
com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109)
~[HikariCP-4.0.3.jar:na] at
org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:159)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:117)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:330)
~[spring-jdbc-5.3.22.jar:5.3.22] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.getProduct(DataSourceHealthIndicator.java:122)
~[spring-boot-actuator-2.7.3.jar:2.7.3] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.doDataSourceHealthCheck(DataSourceHealthIndicator.java:105)
~[spring-boot-actuator-2.7.3.jar:2.7.3] at
org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator.doHealthCheck(DataSourceHealthIndicator.java:100)
~[spring-boot-actuator-2.7.3.jar:2.7.3]
Edit-3
Mr Fatih pointed out some of the changes at the WebSecurityConfiguration. I have changed the code and I am getting this error:
java.lang.IllegalStateException: permitAll only works with either
HttpSecurity.authorizeRequests() or
HttpSecurity.authorizeHttpRequests(). Please define one or the other
but not both.
Here is the change I've made:
/*
* import section have omitted for brevity
*/
#Configuration
#EnableWebSecurity
public class DemoSecurityConfig {
/*
* other codes have omitted for brevity
*/
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
(authz) -> authz.antMatchers("/actuator/**").permitAll().anyRequest().authenticated());
http.authorizeRequests(
configurer -> configurer.antMatchers("/**").hasRole("ADMIN").antMatchers("/**").hasRole("USER"))
.formLogin(configurer -> configurer.loginPage("/showMyLoginPage")
.loginProcessingUrl("/authenticateTheUser").permitAll())
.logout(configurer -> configurer.permitAll())
.exceptionHandling(configurer -> configurer.accessDeniedPage("/access-denied"));
return http.build();
}
}
Here is the console output: https://drive.google.com/file/d/1CtjRBHXVRqirZ0Vt_3FEhx_N9oEwyfFZ/view
You are using the spring-security package for application security. So when you want to access your /actuator endpoints, you need to log in first. If you want to access your /actuator endpoints without logging in, you must configure a security configuration. With the following configuration, you can exclude all endpoints starting with /actuator from security.
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/actuator/**").permitAll().anyRequest().authenticated();
}
}
Since WebSecurityConfigurerAdapter has been deprecated, you can do this as well.
#Configuration
public class SecurityConfiguration {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(autz -> autz
.mvcMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}
** is a wildcard definition and allows you to access this endpoint without logging in, regardless of what comes after the actuator part.
Please Consider using a version for your dependency as far as i remember 1.9.5 RELEASE or 1.9.5 might help in this context , i had the same issue a year ago.

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

Java SpringBoot Keycloak Rest Api Jwt Auth Postman Didn't find publicKey for kid

I'm creating a microservices project. The idea is that a reactjs application get a token from Keycloack and send this jwt token to a springboot rest api in the backend. I'm using docker compose to manage the containers in my local machine.
With Postman I get the token form keycloack, but when I use this token as bearer token to call the rest api with Postman,I'm getting 401.
I configured keycloak, but in the backend, in the logs I found the error:
2021-02-28 10:37:14.134 ERROR 1 --- [nio-8081-exec-4] o.k.a.rotation.AdapterTokenVerifier : Didn't find publicKey for kid: fbb8f5e8-2341-4d1d-82d8-6efe736c90c5
In the logs of keycloak I see:
10:22:19,590 INFO [org.keycloak.keys.DefaultKeyManager] (default task-4) No keys found for realm=master and algorithm=HS256 for use=SIG. Generating keys.
10:22:25,423 INFO [org.keycloak.keys.DefaultKeyManager] (default task-5) No keys found for realm=master and algorithm=RS256 for use=SIG. Generating keys.
10:23:18,927 WARN [org.keycloak.events] (default task-4) type=LOGIN_ERROR, realmId=todo-realm, clientId=todo-app, userId=null, ipAddress=172.29.0.1, error=invalid_client_credentials, grant_type=password
In the Springboot application.properties i put these properties:
keycloak.realm = todo-realm
keycloak.auth-server-url = http://keycloak:8080/auth
keycloak.ssl-required = external
keycloak.resource = todo-app
keycloak.credentials.secret = the secret of the client in keycloack
keycloak.use-resource-role-mappings = true
keycloak.bearer-only = true
In the keycloak I created a realm called: todo-realm. I created a client called todo-app and two roles:
app-user
app-admin
I creted a user, called user1, with the role: app-user.
In my springboot app, the pom is:
<?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.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cammisa.filippo.todolist</groupId>
<artifactId>todo-list</artifactId>
<version>0.0.3-SNAPSHOT</version>
<name>todo-list</name>
<description>Demo project with Spring Boot for A To do List</description>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<docker.image.prefix>fcammisa</docker.image.prefix>
<docker-image-name>todo-list-backend</docker-image-name>
<keycloak.version>12.0.3</keycloak.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- link: http://localhost:8080/api/swagger-ui/index.html?configUrl=/api/v3/api-docs/swagger-config -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-data-rest</artifactId>
<version>1.5.2</version>
</dependency>
<!-- restdocs -->
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-restassured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.cloudyrock.mongock</groupId>
<artifactId>mongock-spring-v5</artifactId>
</dependency>
<dependency>
<groupId>com.github.cloudyrock.mongock</groupId>
<artifactId>mongodb-springdata-v3-driver</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.github.cloudyrock.mongock</groupId>
<artifactId>mongock-bom</artifactId>
<version>4.1.17</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>12.0.3</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>
I created a class to configure keycloack:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/api/todo/todos").hasAnyRole("user")
/*.antMatchers("/api/todo/insert").hasAnyRole("user")
.antMatchers("/api/todo/update").hasAnyRole("user")
.antMatchers("/api/todo/get/{id}").hasAnyRole("user","admin")
.antMatchers("/api/todo/todos").hasAnyRole("user")
.antMatchers("/api/todos/{pageNo}/{pageSize}").hasAnyRole("user")
.antMatchers("/api/todo/delete").hasAnyRole("user")
.antMatchers("/api/todo/delete/{id}").hasAnyRole("user")*/
.anyRequest()
.permitAll();
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
This is my docker compose file:
version: "3.7"
services:
tododb-service:
image: mongo:latest
container_name: tododb
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
MONGO_INITDB_DATABASE: todo
MONGO_INITDB_ROLE: userAdminAnyDatabase
ports:
- 27017:27017
todo-app:
build:
context: .
container_name: todo-app
ports:
- 8081:8081
keycloak-db:
image: postgres
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
keycloak:
image: jboss/keycloak:12.0.3
volumes:
- ./imports:/opt/jboss/keycloak/imports
#command:
# - "-b 0.0.0.0 -Dkeycloak.import=/opt/jboss/keycloak/imports/realm-export.json"
environment:
DB_VENDOR: POSTGRES
DB_ADDR: keycloak-db
DB_DATABASE: keycloak
DB_USER: keycloak
DB_SCHEMA: public
DB_PASSWORD: password
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: password
# Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
#JDBC_PARAMS: "ssl=true"
ports:
- 8080:8080
- 9990:9990
depends_on:
- keycloak-db
Can someone help me to get the result of the rest api using Postaman of my rest api ?
Thank you so much.

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.

Resources