Spring OAUTH: Override CheckTokenEndpoint 'check_token?token=' response map - spring

I would like to override the CheckTokenEndpoint to provide my own custom output as Map to the resource server. I have tried the following, but not working.
Introducing new custom controller for (/oauth/check_token), but Spring rejects this custom and registers its own.
Overriding bean definition for bean 'checkTokenEndpoint' with a
different definition: replacing [Generic bean: class
[com.datami.auth.security.CheckTokenEndpoint]; scope=singleton;
abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;
autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in file
[/usr/local/Cellar/tomcat/8.5.5/libexec/webapps/oauth-server/WEB-INF/classes/com/datami/auth/security/CheckTokenEndpoint.class]]
with [Root bean: class [null]; scope=; abstract=false; lazyInit=false;
autowireMode=3; dependencyCheck=0; autowireCandidate=true;
primary=false;
factoryBeanName=org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
factoryMethodName=checkTokenEndpoint; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerEndpointsConfiguration.class]]
Created my own endpoint with (/oauth/check_custom_token) but not sure autowiring resourceServerTokenServices in the below, #autowire doesn't helped me.
#autowire
private ResourceServerTokenServices resourceServerTokenServices;
Spring has autowired this with DefaultTokenServices.
I can also create new DefaultTokenServices() in my code, but then how to autowire the below inside DefaultTokenServices? again the same problem.
private TokenStore tokenStore;
private ClientDetailsService clientDetailsService;
private TokenEnhancer accessTokenEnhancer;
private AuthenticationManager authenticationManager;
Coul you please help me out.

CheckTokenEndpoint depends on its accessTokenConverter instance to create and return the map.
You could create a custom AccessTokenConverter (maybe extending from OOTB DefaultAccessTokenConverter if needed) and use it like so:
#Configuration
#EnableAuthorizationServer
public class MyAuthConfig extends AuthorizationServerConfigurerAdapter {
...
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.accessTokenConverter(new MyAccessTokenConverter())...
....
Of course, you might want to use a factory method to create your accessTokenConverter instance, which allows you to inject a few properties into the instance etc.
Once done, inside AuthorizationServerEndpointsConfiguration.checkTokenEndpoint you can see that the accessTokenConverter you set above will be passed to the OOTB instance of CheckTokenEndpoint and used to create the map.

Related

Test Controller that uses #QueryDsl Predicate and Page

I have a Controller, that is annotated with #RestController. For GET requests it is implemented like this:
#GetMapping
public Map<String, Object> getFilteredCars(
#QuerydslPredicate(root = Car.class) Predicate predicate,
#RequestParam(name = "page", defaultValue = "0") int page,
#RequestParam(name = "size", defaultValue = "150") int size
) {
return this.carService.getFilteredCars(
predicate,
PageRequest.of(page, size)
);
}
The Controller works fine, I can query with different parameters and get a page with a defined size.
Now I want to test the controller.
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest
class CarControllerTest {
#Mock
private CarService carService;
#InjectMock
private CarController carController;
#BeforeEach
void init(){
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8810;
}
#Test
void givenUrl_whenSuccessOnGetCarsAndReturnsPage_thenCorrect() {
when(this.CarService.getFilteredCars(any(),any()))
.thenReturn(expectedResponse);
given()
.standaloneSetup(new CarController(this.carService))
.when()
.get("/cars?color=red&page=0&size=200")
.then()
.statusCode(200);
}
Running this gave me the exception:
No primary or default constructor found for interface com.querydsl.core.types.Predicate
Like in this question I added
#EnableSpringDataWebSupport
Now I get a new exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException:
Invalid bean definition with name 'pageableResolver' defined in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class]:
Cannot register bean definition
[Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
factoryMethodName=pageableResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class]] for bean 'pageableResolver':
There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration;
factoryMethodName=pageableResolver; initMethodName=null; destroyMethodName=(inferred);
defined in class path resource [org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.class]] bound.
...
I don't understand what is happening. Has anyone an idea, how to resolve the problem?

Not able to execute DataJpaTest

I have a spring-data-jpa repository called TagRepository. My spring-boot version is 2.1.2. I am using H2 dependency with runtime scope and I intend to use it for both the application and integration testing. I want to write a DataJpaTest for the TagRepository. I have written the following code:
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
#DataJpaTest
#ContextConfiguration(classes={TagRepository.class})
public class TagRepositoryTest {
#Autowired
private TestEntityManager testEntityManager;
#Autowired
private TagRepository tagRepository;
#Test
public void findByTagTest() {
Tag tag = new Tag("java");
testEntityManager.persistAndFlush(tag);
Optional<Tag> optionalTag = tagRepository.findByTag(tag.getTag());
if(!optionalTag.isPresent()) {
fail("Tag not found hence test failed");
}
assertThat(optionalTag.get()).isEqualTo(tag);
}
}
However, when I execute the test it says Application failed to start and I get following error:
Invalid bean definition with name 'tagRepository' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'tagRepository': There is already [Generic bean: class [com.upday.task.repository.TagRepository]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
The bean 'tagRepository', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
The test class itself resides in a different package than jpa repository.
Just remove
#ContextConfiguration(classes={TagRepository.class})
from your test.
It is meant for passing a custom #Configuration not a regular bean.
UPD:
When data jpa test and the repository under test resides in a different packages spring runner needed a little hint to scan classes from another place. Pointing out the application class via
#ContextConfiguration(classes={SpringBootApplication.class})
will extend the component scan scope and allow test environment to pick up additional beans.

How to set spring.main.allow-bean-definition-overriding to true in a Spring boot 2.1.0 starter configuration

I maintain a spring-boot-starter that customizes the error attributes returned when, for instance, a unknown end point is called.
This is done by overriding the org.springframework.boot.web.servlet.error.ErrorAttributes bean.
Everything worked fine with 2.0.6, but 2.1.0 disables bean overriding by default, making the starter now fail with the following message.
Invalid bean definition with name 'errorAttributes' defined in class
path resource
[com/mycompany/springboot/starter/config/ErrorsConfig.class]: Cannot
register bean definition [Root bean: class [null]; scope=;
abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0;
autowireCandidate=true; primary=false;
factoryBeanName=com.mycompany.springboot.starter.config.ErrorsConfig;
factoryMethodName=errorAttributes; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[com/mycompany/springboot/starter/config/ErrorsConfig.class]] for bean
'errorAttributes': There is already [Root bean: class [null]; scope=;
abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0;
autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
factoryMethodName=errorAttributes; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.class]]
bound
As explained in documentation setting the spring.main.allow-bean-definition-overriding property to true fixes the problem.
My question is how to do that in the starter (I do not want the users of my starter to have to change their application.properties file, for something that is specific to my starter)?
I tried to a #PropertySource("classpath:/com/mycompany/starter/application.properties") annotation to my #Configuration with that property defined in that file, but it doesn't work.
What am I missing? Is there any way to allow my configuration overriding that bean?
Here is the (simplified) source code of the configuration:
#Configuration
#PropertySource("classpath:/com/mycompany/starter/application.properties")
public class ErrorsConfig {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
#Bean
public ErrorAttributes errorAttributes() {
return new DefaultErrorAttributes() {
#SuppressWarnings("unchecked")
#Override
public Map<String, Object> getErrorAttributes(WebRequest request, boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(request, includeStackTrace);
// CustomeError is a (simplified) bean of the error attributes we should return.
CustomError err = new CustomError("myErrorCode", (String) errorAttributes.get("error"));
return OBJECT_MAPPER.convertValue(err, Map.class);
}
};
}
}
and my resource file com/mycompany/starter/application.properties contains
spring.main.allow-bean-definition-overriding=true
Spring Boot's ErrorAttributes bean is defined by ErrorMvcAutoConfiguration. It is annotated with #ConditionalOnMissingBean so it will back off if an ErrorAttributes bean has already been defined. As the bean defined by your ErrorsConfig class is attempting to override Boot's ErrorAttributes bean rather than causing it to back off, your ErrorsConfig class must be getting processed after Boot's ErrorMvcAutoConfiguration class. This means that you have an ordering problem in your starter.
The order in which auto-configuration classes are processed can be controlled using #AutoConfigureBefore and #AutoConfigureAfter. Assuming that ErrorsConfig is itself an auto-configuration class registered in spring.factories, you can fix your problem by annotating it with #AutoConfigureBefore(ErrorMvcAutoConfiguration.class). With this change in place ErrorsConfig will define its ErrorAttributes bean before ErrorMvcAutoConfiguration attempts to do so which will cause the auto-configuration of Boot's ErrorsAttribute bean to back off.
Easier solution would be to add this property spring.main.allow-bean-definition-overriding=true in the application.properties.
Reference
I have also faced similar issue. But the problem in my case is that, I was using #Entity annotaion in my model class. I was using mongodb for the backend so entity was from Jpa and hence resulted in this issue. Once I removed that it started working

springboot project with multiple module and multiple main class -unit test failing

I am trying to write unit test cases for an existing application with multiple module having main classes in each of them. There are more than one class having \#SpringBootApplication. I have written a simple test case which is failing with following error. How can I continue with my test case for one of them.
java.lang.IllegalStateException: Found multiple
#SpringBootConfiguration annotated classes [Generic bean: class
[com.marketshare.ReportingMainClass]; scope=; abstract=false;
lazyInit=false; autowireMode=0; dependencyCheck=0;
autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in file [C:\My
Data\workspace\services2\microservices\Reporting-Microservice\build\classes\java\main\com\marketshare\ReportingMainClass.class],
Generic bean: class [com.marketshare.SharedMain]; scope=;
abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;
autowireCandidate=true; primary=false; factoryBeanName=null;
factoryMethodName=null; initMethodName=null; destroyMethodName=null;
defined in URL
[jar:file:/C:/My%20Data/workspace/services2/microservices/Shared-Module/build/libs/Shared-Module-1.0-SNAPSHOT.jar!/com/marketshare/SharedMain.class]]
at org.springframework.util.Assert.state(Assert.java:70)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.scanPackage(SpringBootConfigurationFinder.java:69)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.findFromPackage(SpringBootConfigurationFinder.java:59)
at org.springframework.boot.test.context.SpringBootConfigurationFinder.findFromClass(SpringBootConfigurationFinder.java:52)
Here is the code snippet
#RunWith(SpringRunner.class)
#WebMvcTest(CustomReportController.class)
public class CustomReportControllerTest {
}
I just want to unit test my controller. BTW I am new to spring world.
The #RunWith(SpringRunner.class) will load the spring context. To test just the controller you can use
#RunWith(MockitoJUnitRunner.class)
public class CustomReportControllerTest {
}
There is a simple approach, you can creatae a new Spring Boot Application, let's say TestApplication under your test source folder, just like
src\test\java\com\example\TestApplication.java
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan("......").
#EnableAsync
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
and add your package into the #ComponentScan, you can get all the spring boot capacities and only applicable to the test propose.
Add #SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
Use these annotations on the test class and Autowire MockMvc and then you can use mockMvc.perform to test Controller methods

Overriding the InfoEndpoint in Spring Cloud

Originally posted this as an issue in GitHub but might be better suited for this forum...
We are assigning some custom metadata values to our Spring Cloud services that are being registered in Eureka and we now need to have visibility to those values in the Eureka dashboard. I am trying to extend/override the /info endpoint so that our metadata is visible from the Eureka Dashboard which already provides hyperlinks to each registered service's /info endpoint. I had read that I could override the Boot autoconfigured InfoEndpoint by just adding my own version of that bean to the context. I am trying to test with the following configuration bean:
#Configuration
public class EndpointConfig {
#Bean
public InfoEndpoint infoEndpoint() throws Exception {
LinkedHashMap<String, Object> info = new LinkedHashMap<String, Object>();
info.put("name", "value");
return new InfoEndpoint(info);
}
}
When I run my service though and hit its /info endpoint I do not see this test value. I also see this in the log:
2015-04-17 14:54:23,910 main INFO DefaultListableBeanFactory - - - -
Overriding bean definition for bean 'infoEndpoint': replacing [Root
bean: class [null]; scope=; abstract=false; lazyInit=false;
autowireMode=3; dependencyCheck=0; autowireCandidate=true;
primary=false; factoryBeanName=endpointConfig;
factoryMethodName=infoEndpoint; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[com/acme/ecom/items/config/EndpointConfig.class]] with [Root bean:
class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3;
dependencyCheck=0; autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.cloud.autoconfigure.RefreshAutoConfiguration$InfoEndpointRebinderConfiguration;
factoryMethodName=infoEndpoint; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/cloud/autoconfigure/RefreshAutoConfiguration$InfoEndpointRebinderConfiguration.class]]
It appears that my version of the infoEndpoint bean is being replaced with another bean coming from Spring cloud (in org/springframework/cloud/autoconfigure/RefreshAutoConfiguration$InfoEndpointRebinderConfiguration.class).
Am I reading this correctly? And if so how do I prevent it?
Thanks,
Bill
If you put your metadata in info.* e.g. info.myfoo=${eureka.instance.metadataMap.myfoo:none} it will show up in the default /info endpoint.
Don't know if this will actually help but I have this in my application.yml which I can see when I do /info on the service.
info:
component: Service Name
so when i hit the service with /info this is what i see:-
{
"component": "Service Name"
}
Hope this helps.

Resources