Customizing TokenEndpoint in Spring OAuth2 - spring-oauth2

First of all, I have already went through the previous questions on this subject.
I am trying to customize implementations of org.springframework.security.oauth2.provider.endpoint.TokenEndpoint and CheckTokenEndpoint. I can easily do that but I don't know how to plug that customized implementation in Spring Oauth2 Architecture. I am using #EnableAuthorizationServer annotation in my application. Could someone shed some light?

Look at AuthorizationServerEndpointsConfiguration class.
There are #Bean definitions of endpoints.
Try to register your endpoint definition beans with the same names and register them as #Primary #Bean
i.e
#Primary
#Bean
public CustomTokenEndpoint tokenEndpoint() throws Exception {
...
}

Related

Spring Boot 2 Upgrade Issue - Error Page Always returns HTML

I have recently upgraded our project to Spring Boot 2. The App is just a Rest API. And now all our 400 and 500 responses are being returned as html instead of json.
I am defining a custom ErrorAttributes, just like the docs say to do.
#Configuration
public class WebConfig implements WebMvcConfigurer {
...
#Bean
public ErrorAttributes errorAttributes() {
return new DefaultErrorAttributes() {
#Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, true);
return errorAttributes;
}
};
}
...
I would like to debug this issue locally, but I cannot find in the code where Spring Boot makes this decision to add a JSON Response for errors. The docs here: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling says:
For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.
I'm thinking that I must have a Bean defined locally that is causing this not to be configured correctly in the Spring Boot Auto configuration.
I finally figured this out. I think there were some changes in Spring Security 4 to Spring Security 5 that was causing a NPE early in the filter chain for our app. Also, compounding the difficulty of debugging the issue is that with the Spring Boot upgrade, the /error route was forced to be authenticated.
I ended up fixing the NPE, allowing for everyone to see the /error mapping and then making sure ErrorMvcAutoConfiguration was being initialized correctly. All is working now.

How to use values from porperty files in a global context with Junit5 and CitrusExtension

Maybe I'm on the wrong course or totally misunderstanding something.
I've merged a Citrus IntegrationTest from Junit4Runner to Junit5 (with CitrusExtension).
There is an EndpointConfiguration class
#Configuration
#PropertySource("test-setup.properties")
#PropertySource("service-paths.properties")
public class RestEndpointConfig {
#Value("${testenv.host}") //defined in test-setup.properties
private String host;
...
}
And a TestClass
#ExtendWith(CitrusExtension.class)
#RunWith(JUnitPlatform.class)
public class BaseIT{
#CitrusEndpoint
protected HttpClient httpClient;
#Value("${rest.session}") //defined in service-paths.properties
private String sessionPath;
}
In the test class I want to access values defined in the service-paths.properties file.
This worked with JUnit4 but after the changes to JUnit5 it seems that the properties are no longer available in a 'global' context.
Turning the log level to 'debug' shows, that the properties file is loaded.
So my question is: What do I need to change in order to get access to the service-paths properies in my IT classes. What am I missing, what is best practice in this case?
Thanks in advance for any feedback.
Property value resolving via #Value annotation is a core Spring framework feature. So you need to add SpringExtension to your JUnit5 test. You can do this in addition to using the CitrusExtension.

ConnectionFactory exception Camel testing JMS

I'm doing my first steps with Camel and currently working on writing a simple junit test using jms as a transport.
Here is a code I wrote:
public class FirstMockTest extends CamelTestSupport {
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("jms:topic:quote")
.to("mock:quote");
}
};
}
#Test
public void testMessageCount() throws InterruptedException {
MockEndpoint mockEndpoint = getMockEndpoint("mock:quote");
mockEndpoint.setExpectedMessageCount(1);
template.sendBody("jms:topic:quote", "Camel rocks");
mockEndpoint.assertIsSatisfied();
}
}
Because of missing connectionFactory I got the following exception:
org.apache.camel.FailedToCreateRouteException: Failed to create route route1: Route(route1)[[From[jms:topic:quote]] -> [To[mock:quote]]] because of connectionFactory must be specified
I'm able to fix it adding the following lines to my route:
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("vm://localhost?roker.persistent=false");
context.addComponent("jms", JmsComponent.jmsComponent(connectionFactory));
But I don't like I'm adding some components to my context inside the route. Also, If i want to have another route I will need to do it again.
Obviously, there should be another way to tell my test about connection factory.
Thank you in advance!
It's a good idea to define the JMS connection factory outside of your Camel context and, if possible, reuse it. How to do that depends on your component model / execution environment.
If you're using a Java SE version that supports CDI, that would be an obvious choice. You'd define your JMS connection factory as a named component once and inject it everywhere you need it. Have a look at http://camel.apache.org/cdi.html and for testing support at http://camel.apache.org/cdi-testing.html
If you're using Spring, define your connection factory as a spring bean and inject it wherever you need it.
If you're using Java EE on an application server, you'd usually define the JMS connection factory using the mechanisms of that app server. You'd then look up the JMS connection factory using JNDI.
If you're running in an OSGi container, you should define the JMS connection factory in its own bundle and export it as an OSGi service. In the bundle of your Camel context, import that OSGi servide and inject it into the Camel context.
In all above cases you should consider using a pooled JMS connection factory.
For CDI, Spring and OSGi, have a look at: http://activemq.apache.org/maven/5.14.5/apidocs/org/apache/activemq/jms/pool/PooledConnectionFactory.html
For Java EE the way how to set pooling parameters depends on your app server.
Note of caution: for Java SE CDI and Spring there should be only one Camel context per application (you can have many routes, though). So if the JMS connection factory is only used in that one Camel context, there is not much reuse. Despite that I still think it's preferable to define the JMS connection outside of the Camel context in a separate component. It's, well, cleaner.
Since you are writing a junit you can avoid creating a ConnectionFactory if you stub the jms endpoint. You can name the endpoint as stub:jms:topic:quote. Have a look at sample example at link https://github.com/camelinaction/camelinaction2/blob/master/chapter9/mock/src/test/java/camelinaction/FirstMockTest.java

Deep / Nested Dependency Injection in testing

I am using junit, mockito and mockMVC to test the working of a webapp. I am struggling with a dependency whose injecttion I cannot figure out. My webapp structure is as follows.
Class Controller{
#Autowired Service searchService;
#RequestMapping("Search")
public returnType search(#RequestParam("parameter")String parameter){
searchService.doSearch(parameter);
}
}
and the service class
Class Service{
#Autowired Service2 service2;
public returnType doSearch(String parameter){
//some code
service2.call(parameter);
}
}
I need to test the search method for this controller, however service2 is not currently live and hence calls to it have to be mocked. I can mock service2, but cannot figure out how to inject a mock of service2 in my mockMVC instance of controller. As far as I know #InjectMocks in mockito only injects mocks one level deep and not two.
EDIT:
I am using the following to get MockMVC instance of controller
MockMvc controller;
controller = MockMvcBuilders.standaloneSetup(Controller);
What you are essentially want to do is mock a bean.
In your case, you have to mock bean for service2 using #MockBean annotations.
Please refer this article for details.
You don't need that.
Mocking search service will be sufficient as you get the handle of what needs to be done.
Example:
doReturn(...).when(searchService).doSearch(any());
While performing Unit Testing, the developer need to identify the System Under Test and mock/stub all the collaborators.
So, in this case you would write a separate unit test for Controller and Search Service.
Also, read this brilliant article by Martin Fowler - Mocks Aren't Stubs.

Is there a way to use Jackson's SerializationFeature with annotations

I'm trying to use SerializationConfig.Feature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS but I'm not configuring the mapper myself, relying on annotations exclusively and letting Spring's RestTemplate (de)serialize automatically. Is there a way to enable the aforementioned feature in this scenario (i.e. annotations only)?
NOTE: I'm using Jackson 1.x and can't upgrade due to other libs...
With JAX-RS (like DropWizard) you can actually annotated resource endpoints, using #JacksonFeatures
public class Resource {
#Path("item")
#GET
#JacksonFeatures(serializationEnable={ SerializationFeature.WRAP_ROOT_VALUE })
public Pojo getItem(String id) {
...
}
}
I don't know if Spring exposes similar functionality, but it seems possible it does. And if not, it is something they should be able to add to allow per-endpoint setting/clearing of SerializationFeatures / DeserializationFeatures. So if it is not available, maybe file a feature request for Spring project?
Yes, it is possible.
checkout this link: http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/map/annotate/JsonSerialize.html
Example:
#JsonSerialize(using=MySerializer.class,
as=MySubClass.class,
include=JsonSerialize.Inclusion.NON_NULL,
typing=JsonSerialize.Typing.STATIC
)