Unable to get Session in Spring Controller when using Websockets - session

I am using Websockets SockJS with Spring MVC Framework. I tried the Stock Ticker example that's working fine but now I want to get Session in my Controller but I am unable to find a way out.
Client Code:
$scope.socket = new SockJS("ws/ws");
$scope.stompClient = Stomp.over($scope.socket);
$scope.stompClient.connect("guest", "guest",connectCallback, errorCallback);
//in connectCallback
$scope.stompClient.subscribe('/topic/agent-sendstatus', showScreenPop);
Java Code:
#MessageMapping("/topic/agent-sendstatus")
public void testmethod()
{
//How do i get Session here to further implement solution?
template.convertAndSend("/topic/agent-sendstatus","bcd");
}
Please suggest.

In case you are referring to the WebSocket session, Spring 4.1 lets you get the session attributes in a header of the incoming client messages which can be accessed via the SimpMessageHeaderAccessor.
#MessageMapping("/topic/agent-sendstatus")
public void testmethod(SimpMessageHeaderAccessor headerAccessor) {
String sessionId = headerAccessor.getSessionId(); // Session ID
Map<String, Object> attrs = headerAccessor.getSessionAttributes(); // Session Attributes
...
}

I also think you need a interceptor, you will get empty sessionAttributes without it.
You need to add HttpSessionHandshakeInterceptor in the dispatcher-servlet.xml:
<websocket:message-broker
application-destination-prefix="/app"
user-destination-prefix="/user">
<websocket:stomp-endpoint path="/websocket">
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs session-cookie-needed="true" />
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /message" />
</websocket:message-broker>
And then you will be able to get session in the controller:
#MessageMapping("/authorization.action")
public Message authorizationAction(
SimpMessageHeaderAccessor headerAccessor, Message message) {
Map<String, Object> sessionAttributes = headerAccessor.getSessionAttributes();
System.out.println(sessionAttributes);
// Do something with session
return new Message(...);
}

Related

How do you get the Request URL in spring Boot from an AuthorizationFailureEvent

We are using Spring Boot 2.5.2 with Keycloak 14.0. I am trying to log the authorization events in addition to the URL the user called.
I am trying to follow Spring Boot Authentication Auditing Support. The code to retrieve the Request URL is:
private void onAuthorizationFailureEvent(
AuthorizationFailureEvent event) {
Map<String, Object> data = new HashMap<>();
data.put(
"type", event.getAccessDeniedException().getClass().getName());
data.put("message", event.getAccessDeniedException().getMessage());
data.put(
"requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() );
if (event.getAuthentication().getDetails() != null) {
data.put("details",
event.getAuthentication().getDetails());
}
publish(new AuditEvent(event.getAuthentication().getName(),
AUTHORIZATION_FAILURE, data));
}
When I attempt this I am getting a ClassCastException when calling event.getSource(). The source seems to be a ReflectiveMethodInvocation (to my Controller) and not a FilterInvocation. Can anybody explain this? How do I get the request url?

spring integration: How do I call the Spring Integration from Spring Controller?

please, Can you help me?
All of source here it is.
(https://github.com/mcvzone/integration-tcp-test.git)
Thank you.
1. I created a spring integration-tcp-client context xml file.
<int:gateway id="gw"
service-interface="com.example.demo.module.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="localhost"
port="1234"
single-use="true"
so-timeout="10000"/>
<int:channel id="input"/>
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="clientBytes2StringChannel"
connection-factory="client"
request-timeout="10000"
reply-timeout="10000"/>
<int:object-to-string-transformer id="clientBytes2String"
input-channel="clientBytes2StringChannel"/>
2. And I created a RestController.
#RestController
public class TcpController {
final GenericXmlApplicationContext context;
final SimpleGateway simpleGateway;
public TcpController(){
this.context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/integration/tcpClientServerDemo-context.xml");
context.registerShutdownHook();
context.refresh();
this.simpleGateway = context.getBean(SimpleGateway.class);
}
#RequestMapping("/tcp/test")
public String test(String name) {
//SimpleGateway simpleGateway = context.getBean(SimpleGateway.class);
String result = simpleGateway.send(name);
System.out.println("result : " + result);
return result;
}
}
3. I start spring boot and open 1234 port (new ServerSocket(1234)) and I call url.(http://localhost:8080/tcp/test)
4. It result is error.
java.lang.IllegalArgumentException: unable to determine a Message or payload parameter on method
.
.
.
at com.sun.proxy.$Proxy60.send(Unknown Source) ~[na:na]
at com.example.demo.TcpController.test(TcpController.java:25) ~[classes/:na]
It has started to work when I changed your code to this:
#RequestMapping("/tcp/test")
public String test(#RequestBody String name) {
Pay attention to the #RequestBody on the method param. By default Spring MVC does not know to what from the request to map into an argument for this param. So, it is left as null.
On the other hand, when the argument for that gateway call is null, Spring Integration cannot create a Message<?> to send because the payload cannot be null. Therefore you end up with such an exception.
We probably may revise that exception message to make it more obvious for end-users what is going on. Feel free to raise a GH issue on the matter!

Camel: forward message to dynamic destinations (from database)

I am using camel 2.8.4 in my app. my app will receive request from a queue, then the request will be validated by a Validator. Base on the content of the message, the Validator will forward the request to different destinations. Validator will be a POJO bean. Destinations will be get from database (this is a MUST). I prefer to use spring dsl for camelContext.
1. I dont know how to write the validator to forward req to destinations.
2. Can we use something similar like this
<to uri='method=getURI() bean='Validator''> in camelContext
<camelContext>
<route id="route-1">
<from uri="mq:queue:QUEUE"/>
<bean ref="Validator" method="validate"/>
<!--i would be great if we can use <to uri="dynamicURI-from-database"> here -->
</route>
</camelContext>
Class Validator{
public void validate(String req){
if (...)
//get uri1 from database
String uri1=getURI(..);
//forward req to uri1
...........
else
//get uri2 from database
String uri2=getURI(...);
//forward req to uri2
...........
}
public String getURI(..){
......
return uri;
}
}
Use the dynamic URI feature to generate a URI at runtime. You can invoke a processor which sets the URI in exchange and then use that in the to clause.
Something like :
process(new Procesor()
public void process(Exchange exchange){
exchange.setHeader("myURI",someURI);
});
and in the to clause
<to uri="${header.myURI}"/>
Did you have a look at the dynamic recipient list pattern: http://camel.apache.org/recipient-list.html ?
You can use toD provided the destination endpoints are Http APIs. Please refer the link : https://camel.apache.org/components/latest/eips/toD-eip.html

RestEasy client spring integration: can not auto follow redirects

Problem: I can not get RestEasy to automatically follow redirects
I'm using the RestEasy client framework 2.3.4 to consume RESTful JSON services. I'm using the rest easy client spring integration. If I wasn't using spring RestClientProxyFactoryBean to create my services I would set the auto redirect flag on the client request factory
I have tried setting the follow redirect on my HTTP client and following the debug I can see this value is overridden to false by Rest Easy.
Looking at the source code I need to get access to the client invoker that the spring proxy factory creates but it doesn't expose this.
This is like a very common task, surely I am missing something? Cheers.
You should be able to set a custom client executor on the proxybean factory but that also didn't work e.g
#Override
public ClientRequest createRequest(String uriTemplate) {
ClientRequest clientRequest = new ClientRequest(uriTemplate, this);
clientRequest.followRedirects(true);
return clientRequest;
}
#Override
public ClientRequest createRequest(UriBuilder uriBuilder) {
ClientRequest clientRequest = super.createRequest(uriBuilder);
clientRequest.followRedirects(true);
return clientRequest;
}
}
proxyFactoryBean.setClientExecutor(new FollowRedirectsClientExecutor());
In end extending and overriding the Http client (in this case HTTP Component) was needed to make this work e.g.
public HttpUriRequest followRedirects(HttpUriRequest request) {
if (logger.isDebugEnabled()) {
logger.debug("Setting allow redirects");
}
HttpParams p = request.getParams();
HttpClientParams.setRedirecting(p, true);
request.setParams(p);
return request;
}
}
...
#Override
public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throw
s IOException,
ClientProtocolException { ClientProtocolException {
request = followRedirects(request);
...

GWT does not work with Spring REST service

I wrote a Spring REST application. I tested it with curl command and it worked truly.
In another GWT Ajax application I have an RequestBuilder object that it does not work with my Spring Rest: after calling sendRequest method, the event onResponseReceived is fired but the getText method returns an empty string.
this is a part of my spring servlet.xml configuration file
<bean id="jsonmembertemplate"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" >
<property name="contentType" value="text/javascript;charset=UTF-8"/>
<property name="disableCaching" value="false"/>
</bean>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
and a part of my controller class
#RequestMapping(method = RequestMethod.GET, value="/member/get/{memberid}")
public String getMember(Model model, #PathVariable("memberid") int id, HttpServletResponse response) {
model.addAttribute("member", memberDao.get(id));
return "jsonmembertemplate";
}
and gwt code
private RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, "http://localhost:8080/depna-nat-server/member/get/1?");
try {
rb.setHeader("Content-Type", "text/javascript;charset=UTF-8");
rb.sendRequest(null, new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
Window.alert(Integer.toString(response.getStatusCode()));
Window.alert(response.getStatusText());
Window.alert(Integer.toString(response.getText().length()));
area.setText(response.getText());
}
#Override
public void onError(Request request, Throwable exception) {
Window.alert("fail");
}
});
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I have a couple of gwt applications working with json and xml rest services offered by spring, we use spring instead of gwt (rpc or rf) because these services are offered to 3party apps as well.
I started my first project with RequestBuilder and we dind't have any problem, so maybe you have some issue in your code, could you inspect the traffic and post the errors you have?
If you are running a cross-domain issue (statusCode=0 normally means it) , add a filter to your servlet container, take a look to this document.
I finally opted to use gwtquery-ajax and gquery-data-binding because it made really easy to consume these services and to map them to java objects.

Resources