JAX RS and WebSockets with Stomp in Spring Boot conflict - java

I am using Spring-Boot. I would like to use JAX RS as my basic REST-API in combination with WebSockets (using Stomp). However, these two libraries seem to end up in a conflict.
I have the following WebSocketConfig:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").setAllowedOrigins("http://localhost:8000").withSockJS();
}
and the following AppConfig:
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(...);
}
}
The problem occurs, if both classes are commented in. If I comment out AppConfig, my socket-connection will connect without any problems. In the other cases, my REST-Api works but the WebSocket-Connection cannot be established (404 exception). I assume the problem lies in the Jax RS component which probably tries to 'consume' the /hello call and does not find a resource mapped to it.
My question is: How can I tell Jax RS to either ignore the /hello call, so that it gets passed through to the WebSocketMessageBroker or to get it working next to each other?

It's related to Spring-Boot Jersey: allow Jersey to serve static content. The default mapping for the Jersey servlet is /*, which hogs up all the requests. By default it will not forward any routes for which it can't find.
You have couple options:
Change the default mapping for the Jersey servlet. You can do that by either
Adding an #ApplicationPath("/new-root") annotation on top of the ResourceConfig subclass.
Or setting the mapping in the application.properties file, using the following property: spring.jersey.applicationPath
Make Jersey run as a servlet filter instead of a servlet. Doing this allows you to set a property with Jersey that will will allow it forward requested routes to the servlet container, that are not mapped in the Jersey application.
You can see how to work this solution, in this post

Related

How to properly extend WebAuthenticationDetails?

Building Spring Boot application, deploying(by copying to webapps folder while Tomcat is down) to local Tomcat8. Always get an error:
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.
As I understand, problems are while instantiating bean with WebAuthenticationDetails extending:
#Component
public class AuthDetails extends WebAuthenticationDetails{
private final AuthTarget authTarget;
public AuthDetails(HttpServletRequest request) {
super(request);
this.authTarget = AuthTarget.valueOf(request.getParameter("target"));
}
public AuthTarget getAuthTarget(){
return this.authTarget;
}
}
It cannot provide HttpServletRequest for bean constructing, but I don't know how to evade it.
Tried to add RequestContextListener, in xml or as implementation(and marking as #WebListener), no effect.
Out of ideas, how to fix it. Tried example from here: https://github.com/Baeldung/spring-security-registration , no changes - same error at the similar place.
Any help is greatly welcome.
The key was simple: I should define filter bean explicitly in security configuration extends WebSecurityConfigurerAdapter:
#Bean
AuthFilter authFilter() throws Exception{
AuthFilter authFilter = new AuthFilter();
return authFilter;
}
instead of autowiring it.

How to redirect an url ending by ".jsp"

I have a mapped url to /foo.jsp wich redirects to a controller, but it is not handled by spring and returns a 404. It seems that the url is ignored and directly send to tomcat. Is it possible to make spring handle it ?
To reproduce, starting from https://github.com/spring-projects/spring-boot/tree/1.4.x/spring-boot-samples/spring-boot-sample-tomcat7-jsp just add :
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/foo", "/").setStatusCode(HttpStatus.MOVED_PERMANENTLY);
registry.addRedirectViewController("/foo.html", "/").setStatusCode(HttpStatus.MOVED_PERMANENTLY);
registry.addRedirectViewController("/foo.jsp", "/").setStatusCode(HttpStatus.MOVED_PERMANENTLY);
}
}
Then navigating to /foo and /foo.html works as expected, but /foo.jsp returns a 404
Would you use a viewResolver to handle the jsp views.
And segregate html and jsp views differently using this technique.

MessageMapping Handler - No matching methods

I have a Spring webservice #Controller class with a #MessageMapping annotated method as follows:
#MessageMapping("/trade")
public void executeTrade(MarketOrderRequest trade, Principal principal) {
trade.setUserID(principal.getName());
logger.debug("Trade: " + trade);
this.tradeService.executeTrade(trade);
}
I am sending a JSON string message built using the same MarketOrderRequest POJO as is accepted by the server method. With some Key:Value pairs which are set null (but are still present).
The WebSocketConfig class has configured the following endpoints:
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app");
}
When i try to send a message to this messagemapping using this code:
MarketOrderRequest request = new MarketOrderRequest();
//{set request variables..}
StompHeaders someHeaders = new StompHeaders();
someHeaders.putAll(sessionHeaders);
someHeaders.setDestination("/app/trade");
session.send(someHeaders, request);
With headers:
{Cookie=[JSESSIONID=8421F536B639126F84F12E655375D790; Path=/spring-websocket-portfolio/; HttpOnly], version=[1.2], heart-beat=[0,0], user-name=[fabrice], destination=[/app/trade]}
The server then prints that a method cannot be found for the request:
Searching methods to handle SEND /app/trade session=397da625042343b4bac1c913b6d8ec22 application/json;charset=UTF-8
payload={"uuid":null,"symbol":"EUR/USD","price":1.10182,"side":"1","qty":50000,"quoteID"...(truncated)
WebSocketAnnotationMethodMessageHandler[DEBUG] - No matching methods.
The server code is lifted from this project and altered slightly to suit my needs: link
I have added some role-based web socket security in an AbstractSecurityWebSocketMessageBrokerConfigurer implementation class as follows:
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
.simpDestMatchers("/app/**").hasAnyRole("roleA", "roleB", "roleC")
//{some more subscribe dest matchers by role which are working}
}
would this possibly effect the WebSocketAnnotationMethodMessageHandler's attempts to map the request? It is pretty much the only change I have made to the config. My subscribe mappings are working perfectly.
To me it seems that there is a problem finding the method due to either the JSON or Principal parameters. I am sending the correct object type so is this possibly a problem with the User principal? Thanks
There was an error in my WebSocketConfig class.
The #componentscan annotation had the wrong package name. I updated the name to the correct value ( the name of my base package eg "com.my.project" ). Now during deployment in the logs, I can see the controller resources being mapped to the methods in my class.
Eg log output for one method:
Mapped "{[/order],messageType=[MESSAGE]}" onto public void com.my.project.web.PortfolioController.executeOrder(tradeObjects.OrderRequest,java.security.Principal)

Spring MVC 1 to 1 mapping of a URL to .HTML without exposing path

I am using Spring 4.1.5 with Boot 1.2 on a webservice that does not serve up any JSPs. I don't want to add a JSP servlet but I want it to serve up a single canary page that shows in a prettier html type format the information that would be provided at the /manage/health endpoint.
I have a file in webapp/canary/canary.html I want to serve this up from the url: www.mywebservice.com:9343/canary, exactly like that, NOT canary.html
I tried doing this:
#Configuration
public class CanaryConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/canary")
.addResourceLocations("/canary/canary.html");
}
}
That doesn't work however.
It is expecting the handler to provide a file name. So in otherwords the location should be something like: /canary/
and the handler would something like: /canary/**
With that, the URL www.mywebservice.com:9343/canary/canary.html would work like a charm.
HOWEVER, I want the URL to resolve www.mywebservice.com:9343/canary to webapp/canary/canary.html without me having to type the html.
This is really easy in a jsp servlet because you can set the suffix ect...
I looked at ResourceResolver but it didn't make sense to me how I would link that into my current configuration.
It looks like what I want:
Provides mechanisms for resolving an incoming request to an actual Resource and for obtaining the public URL path that clients should use when requesting the resource.
See: ResourceResolver Documentation
Any help would be very beneficial.
Also I am very aware that I can put html in the resources/static and several other places that are automatically configured. That always requires the .html to be typed, which is not what I want in this case so that won't work. Thanks!
You can use view controllers to do it. Here is a sample of it. Hope this helps.
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/canary").setViewName("/canary/canary.html");
}
}
Note: if you are using tomcat, you might have to configure jsp servlet to server html files.
Related post here.
For information sake, the selected answer is the same as the following:
#Controller
public class CanaryController {
#RequestMapping(value="/canary", method=RequestMethod.GET)
public String getCanary() {
return "/canary/canary.html";
}
}
The above code will work as long as canary(or whatever file/folder) is in your webapp folder.
When I tried this I was trying to set the suffix to .html in my YAML (.yml) file and it wasn't working to I thought that it needed to return to a servlet if it is not a RestController. I was mistaken.

Overriding RolesAllowedDynamicFeature in Jersey 2.5.1

Short and sweet:
I want to be able to filter incoming requests to authenticate the user then take the roles defined in my database and use them in the Jersey 2.5.1 Service classes.
e.g.
#RolesAllowed("Custom1", "Custom2")
#Post
.....
Currently I have the following, which seems to work with the basic #PermitAll and #DenyAll annotations, I am just not sure how to overload/what to overload to get some custom code working with Jersey 2.5.1. I've seen examples for Jersey1. Should I just create a request Filter and do it in there and set the securityContext? Any help would be appreciated.
public class TestApi extends ResourceConfig {
public TestApi() {
super(AuthenticateResource.class);
register(RolesAllowedDynamicFeature.class);
}
}
Figured out my problem. Injected Resource Info then pulled out the annotation. This works if it's not pre-matching
#Context
private ResourceInfo resourceInfo;
Annotation[] annotations = resourceInfo.getResourceMethod().getDeclaredAnnotations();
SecurityContext is either set by the underlying container or it's set manually in your application (usually in ContainerRequestFilter). If your container is sophisticated enough to set the correct security context for you (with correct principal) you can go this way. Otherwise create a custom ContainerRequestFilter similar to the one in Jersey example ContainerAuthFilter.

Categories

Resources