I want to implement OAuth2 in my Spring Boot App.
I added
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
Basic config for GitHub (for example):
spring:
security:
oauth2:
client:
registration:
github:
client-id: xxx
client-secret: xxx
And basic WebSecurity config allowing all endpoints:
#Configuration
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.antMatcher("/**").authorizeRequests()
.antMatchers("/**").permitAll()
.and()
.oauth2Login();
}
}
When client-id/secret is not provided, an exception occurs so the config is picked up properly.
But I can't access the oauth login page which should be http://localhost:8080/oauth2/authorization/github, I have an 404 instead.
I'm trying to use aws Cognito`s user authentication with my spring project. I configured Cognito and got a jwt token from it. When I pass the token to my api endpoint I'm getting error 401 (unauthorized).
I'm working on a ms that working in my localhost.
I saw a few examples and I feel like my application.properties is missing something but I'm not sure what.
My application properties :
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_somecode
spring.security.oauth2.client.registration.app1.client-id=my_app_id_in_cognito
My pom has the following security dependencies :
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
My configuration class :
#Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.oauth2ResourceServer().jwt();
}
Tried also to change the application properties according to some spring examples :
spring.security.oauth2.client.registration.cognito.client-id=my_app_id_in_cognito
spring.security.oauth2.client.registration.cognito.client-name=app1
spring.security.oauth2.client.provider.cognito.issuer-uri=https://cognito-idp.eu-west-2.amazonaws.com/eu-west-1_somecode
but then I got the following exception because I was missing the spring.security.oauth2.resourceserver.jwt.jwk-set-uri settings in application.properties :
Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type 'org.springframework.security.oauth2.jwt.JwtDecoder' that could not be found.
The following candidates were found but could not be injected:
- Bean method 'jwtDecoderByIssuerUri' in 'OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration' not loaded because OpenID Connect Issuer URI Condition did not find issuer-uri property
- Bean method 'jwtDecoderByJwkKeySetUri' in 'OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration' not loaded because #ConditionalOnProperty (spring.security.oauth2.resourceserver.jwt.jwk-set-uri) did not find property 'spring.security.oauth2.resourceserver.jwt.jwk-set-uri'
- Bean method 'jwtDecoderByPublicKeyValue' in 'OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration' not loaded because Public Key Value Condition did not find public-key-location property
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.jwt.JwtDecoder' in your configuration.
What am I missing ?
I found this article and tried to use the same setting in the application.properties :
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://cognito-idp.{REGION}.amazonaws.com/{POOL_ID}
I'm currently trying to develop a Spring Boot Rest Api which is secured with keycloak.
I get an error when I try to call a api which the user has to be identify.
The error message is following:
2020-04-10 16:09:00.324 WARN 44525 --- [nio-8080-exec-7]
o.keycloak.adapters.KeycloakDeployment : Failed to load URLs from
https://{{keycloakserver}}.de/auth/realms/{{realm}}/.well-known/openid-configuration
java.lang.RuntimeException: java.lang.RuntimeException: Stub!
at org.keycloak.adapters.KeycloakDeployment.getClient(KeycloakDeployment.java:327) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.KeycloakDeployment.getOidcConfiguration(KeycloakDeployment.java:219) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.KeycloakDeployment.resolveUrls(KeycloakDeployment.java:178) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.KeycloakDeployment.getRealmInfoUrl(KeycloakDeployment.java:232) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.rotation.AdapterTokenVerifier.createVerifier(AdapterTokenVerifier.java:107) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.rotation.AdapterTokenVerifier.verifyToken(AdapterTokenVerifier.java:47) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticateToken(BearerTokenRequestAuthenticator.java:103) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticate(BearerTokenRequestAuthenticator.java:88) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:67) [keycloak-adapter-core-9.0.2.jar:9.0.2]
at org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter.attemptAuthentication(KeycloakAuthenticationProcessingFilter.java:154) [keycloak-spring-security-adapter-9.0.2.jar:9.0.2]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:96) [keycloak-spring-security-adapter-9.0.2.jar:9.0.2]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:97) [spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.10.RELEASE.jar:5.1.10.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
I don't know what Failed to load URLs from means. I can access this side when I click on the link and the configuration file is shown.
Setup
Keycloak:
Keycloak Server is in the web, so no localhost.
I have a realm (test-realm) created
I have a client (test-client) created
I have a user (test-user) created
I have a role in the client (ADMIN) created
I have assigned the role (ADMIN) to the user (test-user)
The client protocol for the client is openid-connect and the access type is confidental.
Spring Boot:
The Spring Boot rest application is running on localhost:8080.
I added in the applications.properties following keycloak configs.
keycloak.realm={{test-realm}}
keycloak.auth-server-url = https://{{keycloakserver}}.de/auth
keycloak.resource = {{test-client}}
keycloak.ssl-required=external
keycloak.bearer-only=true
keycloak.principal-attribute=preferred_username
keycloak.use-resource-role-mappings = true
To make sure the test-user can only access one api call I use following config.
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/getTest")
.hasRole("ADMIN")
.anyRequest()
.authenticated();
}
Tests
When I call http://localhost:8080/getTest with Postman I get a correct 401 Unauthorized.
Then I called the same URL with Authorization and the access token of the logged in test-user.
With this second call I get the error message above.
Does anybody know anything about this?
If I missed a config value that you need to know, just ask.
Thanks for your help.
Edit:
SecurityConfig.java
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
/**
* Created by johannes on 07.04.20 for test App.
*/
#EnableWebSecurity
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
#Configuration
#KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
#Bean
#Primary
public KeycloakConfigResolver keycloakConfigResolver(KeycloakSpringBootProperties properties) {
return new CustomKeycloakSpringBootConfigResolver(properties);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/getTest")
.hasRole("ADMIN")
.anyRequest()
.authenticated();
}
}
CustomKeycloakSpringBootConfigResolver:
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
import org.springframework.context.annotation.Configuration;
/**
* Created by johannes on 10.04.20 for test App.*/
#Configuration
public class CustomKeycloakSpringBootConfigResolver extends KeycloakSpringBootConfigResolver {
private final KeycloakDeployment keycloakDeployment;
public CustomKeycloakSpringBootConfigResolver(KeycloakSpringBootProperties properties) {
keycloakDeployment = KeycloakDeploymentBuilder.build(properties);
}
#Override
public KeycloakDeployment resolve(HttpFacade.Request facade) {
return keycloakDeployment;
}
}
TestController.java (this is just the test getter):
#GetMapping("/getTest")
public #ResponseBody ResponseEntity getTest() {
return ResponseEntity.status(ResponseValues.ITEMDELETEFAILED.getResponseCode()).body(ResponseValues.ITEMDELETEFAILED.getResponseMessage());
}
Request was made with postman, this is the code:
curl --location --request GET 'http://localhost:8080/getTest' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUI...' \
--header 'Cookie: JSESSIONID=41E8E82178FA181817...'
In my case: Realm name was not correct. It is case sensitive. It worked when I change it to:
keycloak.realm = demo
I had written
keycloak.realm = Demo
I have the same problem, and I try a lot to find the answer at google, stackoverflow etc...
Finally, I catch the clue, to make it work, just remove the path of the keycloak.auth-server-url as http://192.168.0.119:8080 instead of http://192.168.0.119:8080/auth or something else.
... : Loaded URLs from http://192.168.0.119:8080/realms/spmia-realm/.well-known/openid-configuration
keycloak.realm=spmia-realm
keycloak.auth-server-url=http://192.168.0.119:8080
keycloak.ssl-required=external
keycloak.resource=ostock
keycloak.credentials.secret=FnUBprsgArHa7PkmR9HPWeXY0nJ22Ks1
keycloak.use-resource-role-mappings=true
keycloak.bearer-only=true
...
keycloak:
image: quay.io/keycloak/keycloak:18.0
restart: on-failure
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB: postgres
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_DB_URL: jdbc:postgresql://database:5432/keycloak
command:
- "start-dev"
depends_on:
database:
condition: service_healthy
ports:
- "8080:8080"
...
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>18.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
I had the same issue, for me it was also connected to a flawed config value.
keycloak.auth-server-url = https://{{keycloakserver}}.de/auth
First I forgot the /auth and then I used http instead of https.
I have been through this issue and solved it as follows
1- make sure of your yaml or properties file in the spring boot application
the following property should be configured based on the keycloak version you use. in my case i used v 17.0.1 and the issue arose because i added it this way
keycloak.auth-server-url=http://localhost:8080/auth rather than this keycloak.auth-server-url=http://localhost:8080
but if you use a lower version than 17 it must be
keycloak.auth-server-url=http://localhost:8080/auth
please make sure that you mentioned the right host and the right port,i just mentioned localhost and the port 8080 because this my case.
I solved the Issue own my own.
I noticed that my spring boot sdk was a android sdk. I don't know how this could happen.
I changed it to the java sdk, and it worked like a charm.
I had a similar issue. In my case, I didn't recognize that there was a single whitespace at the end of my "keycloak.auth-server-url" in my application.properties file.
This way, the keycloak adapter tried to access an invalid URL.
Maybe this helps someone who has a similar issue and finds this thread.
try to change hasRole to hasAuthority or add prefix ROLE_ before the role like this hasRole("ROLE_ADMIN")
I had entered the wrong value for keycloak.auth-server-url.
I'm new with Spring Security and trying to develop Spring Boot app with Google login using OAuth2 which runs under hostname:8080. This app is behind Apache reverse proxy server https://url.com.
Spring Boot version 2.1.0
Spring Security version 5.1.1
build.gradle:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.security:spring-security-oauth2-client")
implementation("org.springframework.security:spring-security-oauth2-jose")
}
application.yml:
oauth2:
client:
registration:
google:
clientId: <clientId>
clientSecret: <clientSecret>
scope: profile, email, openid
server:
use-forward-headers: true
servlet:
session:
cookie:
http-only: false
Spring Security config:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login();
}
}
I request https://url.com
Get redirected to https://accounts.google.com/signin/oauth/
When authenticated get redirected back to
https://url.com/login/oauth2/code/google?state={state}&code={code}&scope=openid+email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.me&authuser=0&session_state={session_state}&prompt=none which timed out with error:
[invalid_token_response] An error occurred while attempting to
retrieve the OAuth 2.0 Access Token Response: I/O error on POST
request for "https://www.googleapis.com/oauth2/v4/token": Connection
timed out (Connection timed out); nested exception is
java.net.ConnectException: Connection timed out (Connection timed out)
Is this error caused by the proxy server settings or boot app? Thanks for help.
Solved. I had to set the JVM parameters:
https.proxyHost=[host]
https.proxyPort=[port]
http.proxyHost=[host]
http.proxyPort=[port]
I am using spring security 3.2 using the namespace configuration, and I want to make all the calls to be https. I know it would decrease the performance by about 1/10, but I still want to implement it. I know you/might achieve this from tomcat itself, but i want to configure it in security.xml
You can configure that https is required by adding requires-channel attribute on each intercept-url. For example:
<http>
<intercept-url pattern="/secure/**" access="ROLE_ADMIN" requires-channel="https"/>
<intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
</http>
You can configure this more concisely using Spring Security Java Configuration. Notice that we can separate the channel configuration from the role mappings. For example:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/**").hasRole("ADMIN")
.anyRequest.hasRole("USER")
.and()
.requiresChannel()
.anyRequest().requiresSecure();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
As of Spring Security 3.2 you also might want to ensure you use Spring Security's headers support. This is enabled by default in Spring Security Java Configuration. In this specific case, the element can add a header called Strict-Transport-Security to the response that ensures that browsers do not even make HTTP requests in the future. For example:
<headers>
<hsts/>
</headers>
You will want to read more about this in the Headers section of the reference.