What is the difference between RestTemplate and its test version? When we do exception handling through #ControllerAdvice, RestTemplate is throwing the exception, but for same flow test version is returning json containing exception details.
So, I wanted to see the summary of differences between them.
The restTemplate give you more possibility, testRestTemplate is only a wrapper of restTemplate which offers you convenient approach, like you said, it doesn't throw exception, but wrap it with json response, such behavior should be implemented by yourself in the real application, but you may not care in the test.
here is the javadoc from testRestTemplate
/**
* Convenient subclass of {#link RestTemplate} that is suitable for integration tests.
* They are fault tolerant, and optionally can carry Basic authentication headers. If
* Apache Http Client 4.3.2 or better is available (recommended) it will be used as the
* client, and by default configured to ignore cookies and redirects.
*
* #author Dave Syer
* #author Phillip Webb
*/
The similar pattern can be found by ReflectionTestUtils and ReflectionUtils
Related
Spring Integration's FtpInboundFileSynchronizer allows for the setting of a Comparator<FTPFile> to allow ordering of the downloads. The documentation says:
Starting with version 5.1, the synchronizer can be provided with a Comparator. This is useful when restricting the number of files fetched with maxFetchSize.
This is fine for #Bean configuration:
#Bean
public FtpInboundFileSynchronizer ftpInboundFileSynchronizer(...)
FtpInboundFileSynchronizer synchronizer = new FtpInboundFileSynchronizer(sessionFactory);
...
synchronizer.setComparator(comparator);
return synchronizer;
}
But if I want to programatically assemble flows, the Java DSL is encouraged.
StandardIntegrationFlow flow = IntegrationFlows
.from(Ftp.inboundAdapter(ftpFileSessionFactory, comparator)
.maxFetchSize(1)
...
The comparator in the Ftp.inboundAdapter(...) factory method is only for the comparison of files locally, after they have been downloaded. There are configuration settings that get passed to the synchronizer here (like remote directory, timestamp, etc.). But there is no setting for the synchronizer equivalent to setting it above.
Solution attempt:
The alternative is to create the synchronizer as non-bean, create the FtpInboundFileSynchronizingMessageSource in a similar way, and use IntegrationFlows.from(source) to assemble the synchronizer results in a runtime exception when the flow is registered with the flow context:
Creating EvaluationContext with no beanFactory
java.lang.RuntimeException: No beanFactory
at org.springframework.integration.expression.ExpressionUtils.createStandardEvaluationContext(ExpressionUtils.java:90) ~[spring-integration-core-5.3.2.RELEASE.jar:5.3.2.RELEASE]
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.afterPropertiesSet(AbstractInboundFileSynchronizer.java:299) ~[spring-integration-file-5.3.2.RELEASE.jar:5.3.2.RELEASE]
That makes sense; the FtpInboundFileSynchronizer is not supposed to be constructed outside of a context. (Though this does appear to work.) But how, in that case, can I dynamically assemble ftp integration flows with a synchronizer configured with a Comparator<FTPFile>?
Looks like we have missed to expose that remoteComparator option in DSL.
Feel free to raise a GH issue or even contribute a fix: https://github.com/spring-projects/spring-integration/issues
As a workaround for dynamic flows, I really would suggest to go a separate FtpInboundFileSynchronizer and FtpInboundFileSynchronizingMessageSource and then use the mentioned IntegrationFlows.from(source). What you probably miss in your configuration is this API:
/**
* Add an object which will be registered as an {#link IntegrationFlow} dependant bean in the
* application context. Usually it is some support component, which needs an application context.
* For example dynamically created connection factories or header mappers for AMQP, JMS, TCP etc.
* #param bean an additional arbitrary bean to register into the application context.
* #return the current builder instance
*/
IntegrationFlowRegistrationBuilder addBean(Object bean);
I mean that FtpInboundFileSynchronizingMessageSource is OK to pass to the from() as a is, but synchronizer has to be added as an extra bean for registration.
Another more fancy way is to consider to use a new feature called DSL extensions: https://docs.spring.io/spring-integration/docs/5.3.2.RELEASE/reference/html/dsl.html#java-dsl-extensions
So, you can extend that FtpInboundChannelAdapterSpec to provide a missed option to configure for an internal synchronizer.
I have endpoints in #RestControllers that look similar to this:
#RestController
#RequestMapping("/rest/x")
public class XApiController
{
// ...
#PostMapping(...)
#PreAuthorize("#apiAuthService.canAccessX(#headers)")
public void saveX(...)
{
// ...
}
}
These endpoints require the developer to make the HttpHeaders object available and name it correctly in the method declaration:
public void saveX(#RequestHeader HttpHeaders headers)
Our problem is that if this last step isn't done, the endpoint only fails at runtime when the endpoint is invoked. This means that issues from large refactors later (say, to change the HttpHeaders argument to HttpServletRequest) aren't easy to identify. Is there any way to tell Spring to validate these expressions are valid on app startup?
I suggest you to create integration tests and then invoke saveX from the test to verify this before you deploy an application.
I would also state my opinion that if you want to have testable code with good quality - try to get rid of SpringEL as soon as possible. In my experience this approach proved as poorly testable, hardly maintainable and also introducing unnecessary complications to your source code.
In modern spring framework there are lots of ways to avoid writing SpringEl.
Spring always validates all beans on start up. But your problem is not within validation your problem is test problem. The process of pre authorization is a runtime job. Spring can not know what to do with this expression spring just checks its syntax over SPEL rules.
You can create tests to check header.
You can increase your IDE inspection level of spring spel to error.
You can simply write a static method to get the headers without a rest parameter.
Spring Boot here. I just read this excellent Baeldung article on Spring Security and implementing basic auth with it. I'm interested in implementing it for a simple REST service (so no UI/webapp) that I need to build.
I'm particularly interested in the BasicAuthenticationEntryPoint impl. In this impl's commence override, the author:
Adds a WWW-Authenticate header to the response; and
Sets the HTTP status code on the response; and
Writes the actual response entity directly to the response; and
Sets the name of the realm
I want to follow this author's example to implement basic auth for my app, but I already have a perfectly functioning ResponseEntityExceptionHandler working for my app:
#ControllerAdvice
public class MyAppExceptionMapper extends ResponseEntityExceptionHandler {
#ExceptionHandler(IllegalArgumentException.class)
#ResponseBody
public ResponseEntity<ErrorResponse> handleIllegalArgumentExeption(IllegalArgumentException iaEx) {
return new ResponseEntity<ErrorResponse>(buildErrorResponse(iaEx,
iaEx.message,
"Please check your request and make sure it contains a valid entity/body."),
HttpStatus.BAD_REQUEST);
}
// other exceptions handled down here, etc.
// TODO: Handle Spring Security-related auth exceptions as well!
}
Is there any way to tie Spring Security and Basic Auth fails into my existing/working ResponseEntityExceptionHandler?
Ideally there's a way to tie my WebSecurityConfigurerAdapter impl into the exception handler such that failed authentication or authorization attempts throw exceptions that are then caught by my exception handler.
My motivation for doing this would be so that my exception handler is the central location for managing and configuring the HTTP response when any exception occurs, whether its auth-related or not.
Is this possible to do, if so, how? And if it is possible, would I need to still add that WWW-Authenticate to the response in my exception handler (why/why not)? Thanks in advance!
I don't think that this is possible. Spring security is applied as a ServletFilter, way before the request ever reaches any #Controller annotated class - thus exceptions thrown by Spring Security cannot be caught by an exception handler (annotated with #ControllerAdvice).
Having had a similar problem, I ended up using a custom org.springframework.security.web.AuthenticationEntryPoint which sends an error, which in turn is forwarded to a custom org.springframework.boot.autoconfigure.web.ErrorController
I'm writing a logging filter that logs all HTTP requests / responses for a web app running in Jersey. ContainerResponseFilter seems to a straight forward solution and I've managed to get it to work.
Next step is to log the IP of the requests. Is there a way to do that from inside the ContainerResponseFilter ?
Short answer:
#Provider
public class YourContextFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest sr;
#Override
public synchronized void filter(ContainerRequestContext request) throws IOException {
/*
* Returns the Internet Protocol (IP) address of the client or
* last proxy that sent the request. For HTTP servlets, same as
* the value of the CGI variable REMOTE_ADDR.
*/
String ip = sr.getRemoteAddr();
// ... log it ...
}
}
EDIT
(regarding the wish for a more detailed answer)
Afaig:
The #Context annotation allows to inject JAX-RS–specific components (one might say you are able to inject contextual information objects). JAX-RS itself is a Java based specification for RESTful Web Services over HTTP protocol. So we are able to inject stuff like:
javax.ws.rs.core.UriInfo
javax.ws.rs.core.Request
javax.ws.rs.core.SecurityContext
and also
javax.servlet.http.HttpServletRequest
In the IOC Chapter of the Jersey docs, you will find these notes:
[...] Jersey implementation allows you to directly inject HttpServletRequest instance into your JAX-RS components [...] - https://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e2401
[...] The exception exists for specific request objects which can injected even into constructor or class fields. For these objects the runtime will inject proxies which are able to simultaneously server more request. These request objects are HttpHeaders, Request, UriInfo, SecurityContext. These proxies can be injected using the #Context annotation. [...]
[...] When deploying a JAX-RS application using servlet then ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse are available using #Context. [...]
And if you do so, you inject in fact a Proxy named org.apache.catalina.connector.RequestFacade (link). This proxy functioned as your direct hotline to your Coyote (HTTP Connector) and thereby to the Coyote request object (link).
Hope this was helpful somehow :) - Have a nice day.
I have searched for tutorials on this topics, but all of them are outdated. Could anyone provide to me any links, or samples about integrating Spring security into GWT?
First of all, you have to bear in mind that GWT application is turned into javascript running on client-side, so there is nothing you can really do about securing some resources out there. All sensitive information should be stored on server side (as in every other case, not only for GWT), so the right way is to think of Spring Security integration from the point of view of application services layer and integrating that security with communication protocol you use - in case of GWT it is request factory in most cases.
The solution is not very simple, but I could not do it in any better way... any refinement suggestions are welcome.
You need to start with creating GWT ServiceLayerDecorator that will connect the world of request factory with world of Spring. Overwrite createServiceInstance method taking name of spring service class to be invoked from ServiceName annotation value and return instance of this service (you need to obtain it from Spring ApplicationContext):
final Class<?> serviceClass = requestContext.getAnnotation(ServiceName.class).value();
return appContext.getBean(serviceClass);
Also, you need to override superclass invoke(Method, Object...) method in order to catch all thrown runtime exceptions.
Caught exception cause should be analyzed, if it's an instance of Spring Security AccessDeniedException. If so, exception cause should be rethrown. In such case, GWT will not serialize exception into string, but rethrow it again, thus, dispatcher servlet can handle it by setting appropriate HTTP response status code. All other types of exceptions will be serialized by GWT into String.
Actually, you could catch only GWT ReportableException, but unfortunately it has package access modifier (heh... GWT is not so easily extensible). Catching all runtime exceptions is much more safe (althouth not very elegant, we have no choice) - if GWT implementation change, this code will still work fine.
Now you need to plug in your decorator. You can do it easily by extending request factory servlet and defining your's servlet constructor as follows:
public MyRequestFactoryServlet() {
this(new DefaultExceptionHandler(), new SpringServiceLayerDecorator());
}
The last thing - you need to do a dirty hack and overwrite request factory servlet doPost method changing the way how it handles exceptions - by default, exception is serialized into string and server sends 500 status code. Not all exceptions should result in 500 s.c - for example security exceptions should result in unauthorized status code. So what you need to do is to overwrite exception handling mechanism in the following way:
catch (RuntimeException e) {
if (e instanceof AccessDeniedException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
} else {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
LOG.log(Level.SEVERE, "Unexpected error", e);
}
}
Instead of extending classes, you can try to use some 'around' aspects - it is cleaner solution in this case.
That's it! Now you can annotate your application services layer as usual with Spring Security annotations (#Secured and so forth).
I know - it's all complicated, but Google's request factory is hardly extendable. Guys did a great work about communication protocol, but design of this library is just terrible. Of course the client-side code has some limitations (it is compiled to java script), but server-side code could be designed much better...