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.
Related
I am using spring boot 2.0.7 Release and spring-boot-starter-mail-2.0.7.Release.
I am autowiring javaMailsender inside the class working ok on windows while trying to deploy on Unix getting belwo issue
APPLICATION FAILED TO START
***************************
Description:
Field javaMailSender in com.fti.di.capstock.tran.pub.email.SendEmail required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.mail.javamail.JavaMailSender' in your configuration.
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Component;
import com.fti.di.capstock.tran.pub.constants.ApplicationFlowConstants;
import com.fti.di.integration.constants.IntegrationConstants;
import com.fti.di.integration.util.StringUtil;
#Component("sendEmail")
public class SendEmail {
#Autowired
private JavaMailSender javaMailSender;
#Autowired
Environment env;
#ServiceActivator
you've to provide the mail configuration in application.properties
spring.mail.host=MAIL_SERVER_IP
spring.mail.port=MAIL_SERVER_PORT
spring.mail.userName=USER_NAME
spring.mail.password=THE_PASSWORD
and if authentication not enable in server then
remove userName and password and add this
spring.mail.properties.mail.smtp.auth=false
spring.mail.properties.mail.smtp.starttls.enable=false
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
#Configuration
public class Config {
#Bean
public JavaMailSender javaMailSender() {
return new JavaMailSenderImpl();
}
}
You can also return an instance of JavaMailSenderImpl() from your #Bean above saving you the hustle of having to implement a bunch of methods when you try to return the actual JavaMailSender() class.
Declare a #Bean of the type JavaMailSender in a Configuration class (This is useful when you want to inject a class which is not part of your Spring Context, like a class that belongs to a 3rd-party lib, which happens to be your case). For example:
#Configuration
public class MyConfig {
#Bean
public JavaMailSender javaMailSender() {
return new JavaMailSender();
}
}
Make sure that the you have set the right properties under application.properties as well.
Also, take a look into this question, as I believe this is a duplicate (if it's not, I am sorry)
In My project i was reading email properties file like hostname, port etc from spring config server (Spring cloud).
I was missing a dependency at client end. Once i added that Dependency.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
JavamailSender class able to read those properties and worked fine.
In spring boot we need not define JavaMailSender bean manually. spring boot does itself.
the best answer I ve found was to check if you have a type in your application.properties:
spring.mail.host
spring.mail.username
spring.mail.password
spring.mail.port
Check the response of gleidson cardoso da silva from Could not autowire org.springframework.mail.javamail.JavaMailSender
This error occurred due to the missing following properties in the application.yml file.
mail:
host: localhost
port: 1025
username: hello
password: hello
properties:
mail:
smtp:
ssl:
trust: "*"
auth: true
starttls:
enable: true
connectiontimeout: 5000
timeout: 3000
writetimeout: 5000
I have this error and it was related to missing properties in application.yml in the test folder.
I am using dropwizard 1.2.4 with log4j 1.2.17. I have followed the instructions as mentioned below
https://github.com/arteam/dropwizard-nologback/
It is throwing the exception like below during unit testing.
java.lang.NoClassDefFoundError: ch/qos/logback/core/filter/Filter
at io.dropwizard.testing.junit.ResourceTestRule.<clinit>(ResourceTestRule.java:34)
at com.vnera.restapilayer.api.resources.ApiInfoControllerTest.<clinit>(ApiInfoControllerTest.java:25)
at sun.misc.Unsafe.ensureClassInitialized(Native Method)
at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:43)
at sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:156)
at java.lang.reflect.Field.acquireFieldAccessor(Field.java:1088)
at java.lang.reflect.Field.getFieldAccessor(Field.java:1069)
at java.lang.reflect.Field.get(Field.java:393)
at org.junit.runners.model.FrameworkField.get(FrameworkField.java:73)
at org.junit.runners.model.TestClass.getAnnotatedFieldValues(TestClass.java:230)
at org.junit.runners.ParentRunner.classRules(ParentRunner.java:255)
at org.junit.runners.ParentRunner.withClassRules(ParentRunner.java:244)
at org.junit.runners.ParentRunner.classBlock(ParentRunner.java:194)
at org.junit.runners.ParentRunner.run(ParentRunner.java:362)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassNotFoundException: ch.qos.logback.core.filter.Filter
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 19 more
My test code looks like below
import io.dropwizard.testing.junit.ResourceTestRule;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import javax.ws.rs.core.Response;
import static org.mockito.Mockito.mock;
#Category(value = UnitTest.class)
public class ApiInfoControllerTest {
private static ApiNonFunctionalHandler nonFunctionalHandler = mock(ApiNonFunctionalHandler.class);
private static ApiFilter apiFilter = new ApiFilter(nonFunctionalHandler);
private static final String authToken = "NetworkInsight xTyAGJmZ8nU8yJDP7LnA8Q==";
#ClassRule
public static final ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new ApiInfoController())
.addProvider(apiFilter).build();
#Test
public void testApiVersion() throws Exception {
Response response = resources.client()
.target(ApiConstants.INFO_BASE_URL + "/version")
.request()
.header("Authorization", authToken)
.buildGet().invoke();
Assert.assertNotNull(response);
Assert.assertEquals(response.toString(), Response.Status.OK.getStatusCode(), response.getStatus());
final VersionResponse actualError = response.readEntity(VersionResponse.class);
Assert.assertEquals(actualError.getApiVersion(), ApiConstants.API_VERSION);
}
}
My main application is working fine. The configuration.yaml for main application looks like below
# Change default server ports
server:
applicationConnectors:
- type: http
port: 8123
adminConnectors:
- type: http
port: 8124
requestLog:
type: external
logging:
type: external
Can someone let me know what could be going wrong and how can I get around this?
EDIT
Output of mvn dependency:tree is placed here as I am hitting the character limit here.
This is a bug in dropwizard 1.2.4 as discussed below
https://github.com/dropwizard/dropwizard/pull/2338
I was trying to implement Redis with Spring with XML based configuration. My configuration file like as below:
<!-- declare Redis Cache Manager -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"
c:template-ref="redisTemplate" />
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="172.17.0.2" p:use-pool="true" />
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory" />
And my cache definitions like:
#Cacheable(value = "my-cache-key", key = "{#argSomeObj, #argSomeString, #argSomeInt}")
public MyAwesomeDTO getSomeResult(SomeObject argSomeObj, String argSomeString, int argSomeInt, Request argRequest)
{
// this part calculates and returns some values regarding to given parameters
return awesomeDTO;
}
When I hit this function in first time I got error which is stated below. When I try second time, it works properly and stores in Redis.
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
at redis.clients.jedis.JedisPool.returnBrokenResource(JedisPool.java:239)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:255)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:16)
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:257)
at org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection(RedisConnectionUtils.java:206)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:205)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:140)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:125)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doPut(AbstractCacheInvoker.java:82)
at org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:651)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:358)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
Is there anybody knows how can I fix this error?
Here is the full stack trace:
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] ERROR com.tokmak.frontend.MyApplication - A 500 error (redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool) occured on URL [https://www.vtokmak.office.com:8443/some-url], userAgent [Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36]
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
at redis.clients.jedis.JedisPool.returnBrokenResource(JedisPool.java:239)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:255)
at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:16)
at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:257)
at org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection(RedisConnectionUtils.java:206)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:205)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:140)
at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:125)
at org.springframework.cache.interceptor.AbstractCacheInvoker.doPut(AbstractCacheInvoker.java:82)
at org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:651)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:358)
at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
at com.tokmak.frontend2.service.misc.world.WorldService$$EnhancerBySpringCGLIB$$8a70244e.getWorld(<generated>)
at com.tokmak.frontend2.controller.world.AbstractWorldController.handle(AbstractWorldController.java:69)
at com.tokmak.frontend.Router.getView(Router.java:1069)
at com.tokmak.frontend.Router.routeRequest(Router.java:320)
at com.tokmak.webframework.RouterServlet.doRequestProcessingUnchecked(RouterServlet.java:145)
at com.tokmak.webframework.RouterServlet.doRequestProcessing(RouterServlet.java:93)
at com.tokmak.webframework.RouterServlet.doGet(RouterServlet.java:68)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Invalidated object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.invalidateObject(GenericObjectPool.java:640)
at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:101)
... 44 more
// 01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.webframework.RouterServlet - Exception [/some-url], message: "Could not return the resource to the pool"]
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - I have to make use of static fail over [http://192.168.3.14/]...
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - ... but since there is a static fail-over URL present in config, I try to load the data from [http://192.168.3.14/www.vtokmak.office.com:8443/some-url]
01-30 12:34:35 [Thread#12:34:35.259:https://www.vtokmak.office.com:8443/some-url] WARN com.tokmak.frontend.Router - fuck, even though I have a static fail-over URL, I failed!
Jan 30, 2018 12:34:36 PM org.apache.jasper.compiler.TldLocationsCache tldScanJar
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
although I can't see your code, I've seen this happen when you try to close a jedis instance twice, without noticing. for eg:
Jedis implements Closable and when inside a try-with-Resources it will be automatically closed.
try(Jedis jedis = getJedis()){
}catch{...}
thus if you also call jedis.close() it will throw that error.
either
try{
Jedis jedis = getJedis();
}catch(){
}finally{
jedis.close()
}
or see if you're calling close() more than once
As #mp911de mentioned here, this problem was related to Spring Data Redis version. When I upgraded it resolved.
Here is the java based configuration. Try and share results.
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import redis.clients.jedis.JedisPoolConfig;
#Configuration
#EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
#Override
#Bean
public CacheManager cacheManager() {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate());
cacheManager.setUsePrefix(true);
//cacheManager.setCacheNames(getCacheNames());
return cacheManager;
}
#Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setExposeConnection(true);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
om.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
om.setSerializationInclusion(Include.NON_NULL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
return redisTemplate;
}
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisPoolConfig config = new JedisPoolConfig();
config.setTestOnBorrow(false);
config.setTestOnCreate(false);
config.setTestOnReturn(false);
config.setTestWhileIdle(false);
config.setMaxTotal(1000);
config.setMaxIdle(1000);
config.setMinIdle(0);
config.setMaxWaitMillis(10000);
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.setHostName("172.17.0.2");
//connectionFactory.setPort(6379);
connectionFactory.setUsePool(true);
connectionFactory.setPoolConfig(config);
return connectionFactory;
}
#Override
#Bean
public KeyGenerator keyGenerator() {
return new SimpleKeyGenerator();
}
}
I am trying to create a Spring Boot REST application. When I deploy my application, it authentication is required and it is asking me for user name and password. How can I bypass this or how can I add a user name and password for authentication?
Do I need to remove security entry in pom?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
If you don't want to use authentication at all, you should remove the dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
See Spring Boot Reference Guide:
If Spring Security is on the classpath then web applications will be secure by default with ‘basic’ authentication on all HTTP endpoints.
No need of removing security from pom.xml. In your project, you can try something like below. Try to create SecurityConfig which will extend WebSecurityConfigurerAdapter and provide some user name and password and later you can customize it.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("user")
.roles("USER")
.and()
.withUser("user2")
.password("secret2")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated();
http
.httpBasic();
http
.csrf().disable();
}
}
public #interface EnableWebMvcSecurity {
}
Apart from other two answers - default username is 'user' and password will be printed in the console each time you start your server like below -
2019-08-31 23:58:16.417 INFO 12528 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: 1ab46edf-332a-42de-ae11-70dc138c65db
Simply use these credentials to login.
Note - If you fine-tune your logging configuration, ensure that the org.springframework.boot.autoconfigure.security category is set to log INFO-level messages. Otherwise, the default password is not printed.
if you wish to configure a username/password of your choice then you can do so in application.properties file.
spring.security.user.name=username
spring.security.user.password=password
Now spring security will not generate a new password each time you boot the application.
Note: When using postman to send requests, go to authorization> select "basic auth"> Enter the username and password so authentication details can be sent along with each request. If using browser, there should be a login page.
I've been working for a few days to attempt to implement oauth2 protection on a REST API. I've tried a ton of different configurations but still haven't managed to get it to work.
I'm proving the code that I have right now, but I'm in no way married to this implementation. If you can show me some radically different way to accomplish what I want to accomplish, great.
My flow looks like this:
Client checks Auth Server, gets token.
Client sends token to Resource Server.
Resource Server uses Auth Server to make sure that token is valid.
The Auth Server works fine. I'm having trouble configuring the Resource Server.
Configs on Resource Server
Here's some of my configs. I have this bean:
Ouath Rest Template
#EnableOAuth2Client
#Configuration
#Import({PropertiesConfig.class}) //Imports properties from properties files.
public class OauthRestTemplateConfig {
#Bean
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2ResourceDetails(), oauth2ClientContext);
return template;
}
#Bean
OAuth2ProtectedResourceDetails oauth2ResourceDetails() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("theOauth");
details.setClientId("clientID");
details.setClientSecret("SecretKey");
details.setAccessTokenUri("https://theAuthenticationServer.com/oauthserver/oauth2/token");
details.setUserAuthorizationUri("https://theAuthenticationServer.com/oauthserver/oauth2/token");
details.setTokenName("oauth_token");
details.setPreEstablishedRedirectUri("http://localhost/login");
details.setUseCurrentUri(true);
return details;
}
}
Security Config
I use that bean in my main security config in Resource Server:
#Slf4j
#Configuration
#EnableWebSecurity
#EnableOAuth2Client
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true, proxyTargetClass = true)
#Import({PropertiesConfig.class, OauthRestTemplateConfig.class})
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("oAuth2RestTemplate")
private OAuth2RestTemplate oAuth2RestTemplate;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.accessDecisionManager(accessDecisionManager()) //This is a WebExpressionVoter. I don't think it's related to the problem so didn't include the source.
.antMatchers("/login").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().authenticated();
http
.exceptionHandling()
.authenticationEntryPoint(delegatingAuthenticationEntryPoint());
http
.addFilterBefore(new OAuth2ClientContextFilter(), BasicAuthenticationFilter.class)
.addFilterAfter(oauth2ClientAuthenticationProcessingFilter(), OAuth2ClientContextFilter.class)
;
}
private OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter() {
OAuth2ClientAuthenticationProcessingFilter
daFilter = new OAuth2ClientAuthenticationProcessingFilter("/api/**");
daFilter.setRestTemplate(oAuth2RestTemplate);
daFilter.setTokenServices(inMemoryTokenServices());
return daFilter;
}
private DefaultTokenServices inMemoryTokenServices() {
InMemoryTokenStore tok = new InMemoryTokenStore();
DefaultTokenServices tokenService = new DefaultTokenServices();
tokenService.setTokenStore(tok);
return tokenService;
}
}
Extra stuff in Security Config
Aaand, some of the beans which I believe are less relevant, but here they are in case you need them:
#Bean
public DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint() {
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> matchers =
Maps.newLinkedHashMap();
//Match all HTTP methods
matchers.put(new RegexRequestMatcher("\\/api\\/v\\d+\\/.*", null), oAuth2AuthenticationEntryPoint());
matchers.put(AnyRequestMatcher.INSTANCE, casAuthenticationEntryPoint());
DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(matchers);
entryPoint.setDefaultEntryPoint(casAuthenticationEntryPoint());
return entryPoint;
}
#Bean(name = "casEntryPoint")
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casUrl + "/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
Error
Resource Server starts up just fine. Client gets its auth token from theAuthenticationServer.com and sends it in the request header to an api url. And I get the following error:
HTTP Status 500 - Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Exception report
Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
The server encountered an internal error that prevented it from fulfilling this request.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
com.sun.proxy.$Proxy26.getAccessToken(Unknown Source)
org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause
<pre>java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
com.sun.proxy.$Proxy26.getAccessToken(Unknown Source)
org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
I've tried a lot of different configs, looked up a ton of resources online, and I've gotten nowhere. Am I using the right classes? Any idea what configs I might need to change?
An even easier way to enable the request context listener is to add a bean annotation into your app.
#Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
I ended up resolving this thing after looking into Spring documentation.
It turned out that the scope context didn't actually exist in my app, because I hadn't initialized it.
I initialized it by adding this listener:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
I'm proving the code that I have right now, but I'm in no way married
to this implementation. If you can show me some radically different
way to accomplish what I want to accomplish, great
If your main problem is implementing the Resource Server and also, you are open to totally different solutions, you can use Spring Boot's resource server auto configurations. This way you would have a ResourceServerConfiguration such as following:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated();
// you can put your application specific configurations here
// here i'm just authenticating every request
}
}
With an application.yml config file in your src/main/resources:
security:
oauth2:
client:
client-id: client
client-secret: secret
resource:
token-info-uri: http://localhost:8888/oauth/check_token
You should add your client-id, client-secret and token-info-uri there. token-info-uri is the endpoint on Authorization Server that our resource server is going to consult about the validity of passed Access Tokens.
With these arrangements, if the client fire a request to, say, /api/greet API:
GET /api/greet HTTP/1.1
Host: localhost:8080
Authorization: bearer cef63a29-f9aa-4dcf-9155-41fb035a6cdb
Our resource server will extract the Bearer access token from the request and send the following request to the authorization server to validate the access token:
GET /oauth/check_token?token=cef63a29-f9aa-4dcf-9155-41fb035a6cdb HTTP/1.1
Host: localhost:8888
Authorization: basic base64(client-id:client-secret)
If token was valid, authorization server send a 200 OK response with a JSON body like following:
{"exp":1457684735,"user_name":"me","authorities":["ROLE_USER"],"client_id":"client","scope":["auth"]}
Otherwise, it will return a 4xx Client Error.
This was a maven project with a pom.xml like following:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.3.RELEASE</version>
</parent>
<dependencies>
<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.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
</dependencies>
And a typical Application class:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
You can check out the spring boot documentation on resource server auto configurations here.
I believe that the root of issue is that you create the OAuth2ClientAuthenticationProcessingFilter and OAuth2ClientContextFilter with new operator.
If you look at the stacktrace
org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
com.sun.proxy.$Proxy26.getAccessToken(Unknown Source)
org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94)
there's a chain how it goes from OAuth2ClientAuthenticationProcessingFilter to JdkDynamicAopProxy and tries to get the bean. And I can assume because of that bean was created out of Spring container, it can't get the bean from the session scope.
Try to wrap your filters into #Bean annotation so to put them into context. Also, i believe it worth being set the correct scope: the request would match best here.
I faced the same problem when using spring-boot 1.4.1 with spock-spring 1.1-groovy-2.4-rc-2. The easiest way to fix it is to use Spock 1.0.
There is a bug reported already:
https://github.com/spockframework/spock/issues/655
public class ContextAwareCallable implements Callable {
private Callable<T> task;
private RequestAttributes context;
public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
this.task = task;
this.context = cloneRequestAttributes(context);
}
#Override
public T call() throws Exception {
if (context != null) {
RequestContextHolder.setRequestAttributes(context);
}
try {
return task.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
private RequestAttributes cloneRequestAttributes(RequestAttributes requestAttributes) {
RequestAttributes clonedRequestAttribute = null;
try {
clonedRequestAttribute =
new ServletRequestAttributes(((ServletRequestAttributes) requestAttributes).getRequest(),
((ServletRequestAttributes) requestAttributes).getResponse());
if (requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST).length > 0) {
for (String name : requestAttributes.getAttributeNames(RequestAttributes.SCOPE_REQUEST)) {
clonedRequestAttribute.setAttribute(name,
requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST),
RequestAttributes.SCOPE_REQUEST);
}
}
return clonedRequestAttribute;
} catch (Exception e) {
return requestAttributes;
}
}
}
Then create executor
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
#Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
#Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
}