MessageMapping Handler - No matching methods - java

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)

Related

Camel Salesforce Authentication challenge without WWW-Authenticate header

I am trying to push/get values to salesforce using camel with java. When I try to send data I get the following error :
HTTP protocol violation: Authentication challenge without WWW-Authenticate header
The strange part is that it work like a charm when I subscribe to data with routes /data/AccountChangeEvent
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() {
from("salesforce:/data/AccountChangeEvent?replayId=-2")
.bean(clientService, "accountChange");
from("direct:updateSalesforce")
.to("salesforce:createSObject?sObjectName=Account");
}
}
public class SalesforcePublisherService {
#Autowired
CamelContext camelContext;
public void publishToSalesforce(String endpointUri, Object body) {
Map<String, Object> values = new HashMap<>();
// [...] Putting some values
camelContext.createProducerTemplate().requestBody("direct:updateSalesforce", values);
}
}
I found out what the problem was.
First I found out that the error was really different from what was written. In order to investigate on that part I activated Jetty's logs with :
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-Dorg.eclipse.jetty.LEVEL=DEBUG
Then I reproduce the call on my postman and I got the message from this 401 error. After some investigation the problem was related with how I generated my refresh token:
I shouldn't have used the scope "refresh_token" when generating the salesforces token (actually no scope is needed).

Content-Type is missing with Spring GET/POST method

I am new to Spring and I am trying to do the basic GET and POST method.
This is how I am trying to do the methods:
#RestController
public class DeskController {
#Autowired
private DeskDao dao;
#GetMapping("desks")
public List<Desk> getDesks() {
System.out.println(dao.findById(1L));
return dao.findAll();
}
#PostMapping("desks")
public Desk save(#RequestBody #Valid Desk desk) {
Desk deskObj = dao.save(desk);
System.out.println(deskObj);
return deskObj;
}
When I am calling the POST method like this I get the pring with the actual object that I had called it with so it is working fine, but I also get this error:
javax.ws.rs.ProcessingException: Content-Type is missing
And when trying to call GET it tells me that:
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported
I am aware that I have not included the whole code, but I will add what is needed to resolve this error since there are a lot of classes.
My questions are, what do I do against the first error and why is GET method not supported?
Two things you need to change :
Use a / to indicate that for this path you will perform an
operation. For eg : (/desks)
Use the annotation #Consumes to
indicate that this method accepts the payload in particular format. For eg : #Consumes(MediaType.APPLICATION_JSON) annotated over your save() method.

Authenticate spring websocket via MessageMapping

Problem
I have set up a stomp websocket on spring, and have endpoints defined via the #MessageMapping annotation.
I had read that #PreAuthorize could be used to authorize on a per mapping basis but this doesn't appear to work. When using the #PreAuthorize, the request is not denied when the user is not in a specific role.
Code
#PreAuthorize("hasRole('ROLE_ADMIN')")
#MessageMapping(value="/addComment/{ID}")
public void addComment(#DestinationVariable Integer ID, String content, Principal principal)
throws Exception {
//Do stuff with ID,content etc
}
I currently have it set up like so
#Configuration
public class WebSocketSecurityConfig extends
AbstractSecurityWebSocketMessageBrokerConfigurer {
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpDestMatchers("/put/addComment/**").hasRole("ADMIN");
}
}
Although would prefer to annotate on each mapping since it is clearer for me.
Question(s)
Can preauthorize be used with mappings?
If so is there a reason that it is not working in the above example?
If not, is there a way to do this per mapping, instead of in the configurer?
Extra
Using Spring 4
Any more information needed let me know

Passing arguments to a secured dropwizard resource

I have a resource, which is secured, if I remove the authentication, it appears to work, but then without the security, then what is the point?
Here is my code :
#POST
#Path("/secured")
#Timed
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#UnitOfWork
#RolesAllowed("mainUser")
public Response aliveSecure(#Auth User user, CustomRequest test)
{
CustomResponse resp = new CustomResponse();
System.out.println(test.getMessage());
return Response.status(Response.Status.ACCEPTED).entity(resp).build();
}
The CustomRequest and CustomResponse types are pretty standard POJOs, they just hold a string called "Message" - they are actually identical, but this is just an exercise I am trying to complete for the sake of learning DropWizard.
Now, if I remove the #Auth stuff here, and the #RolesAllowed, etc - making it a insecure, then the method performs as normal - but as is, this is the error I get when trying to start the application.
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
! [[FATAL] No injection source found for a parameter of type public CustomRequest at index 0.;
The auth manual reads it clear -
If you want to use #Auth to inject a custom principal type into your
resource.
Hence you shall ensure adding the following to your Service that extends io.dropwizard.Application
#Override
public void run(SomeConfigThatExtendsConfiguration config, Environment environment) throws Exception {
....
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
}

How to intercept a request in Jersey using Annotations?

I'm using Jersey to build a REST API with your standard annotation based routing.
My question is, how can I use a "custom annotation" (in this case #InternalOnly) to intercept a request and run code before the request hits the resource and the // DO STUFF block is executed?
#Path("app")
#Produces(MediaType.APPLICATION_JSON)
public final class SomeResource {
#GET
#Path("something")
#InternalOnly
public Response getSomething() {
// DO STUFF
}
}
I would then have another class that would handle the #InternalOnly header...
public final class InternalOnlyHandler implements SomethingProbably {
public void handle(Object someContext) {
// HANDLE INTERNAL ONLY AUTHENTICATION
}
}
My purpose is basically I need certain API resources to be available internally ONLY and others publicly available and the Authentication is slightly different for both so registering a simple ContainerRequestFilter won't do the job.
I can't figure this out -- please help!

Categories

Resources