Spring and Netflix DGS: Access SecurityContext from DgsSubscription Method - spring

We have a custom SecurityService class that internally accesses the current SecurityContext and RequestAttributes via SecurityContextHolder and RequestContextHolder for every method call of the service.
Imagine the custom class User returned from securityService.getUser();
Given the following code:
#DgsSubscription
public Publisher<String> test() {
String s = securityService.getUser().getName();
return Flux.interval(Duration.ofSeconds(5)).map(t -> s);
}
That periodically triggers the test subscription and returns the User name.
I get the following error when a client tries to subscribe:
Exception while fetching data (/test) : 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Apparently the test method is run in a new thread?
How do I make both context available to this thread?
SecurityService is autowired into the Datafetcher.

Related

HttpServletRequest throws error when used within Aspect

I have a method which has an aspect. When I try to #Autowire HttpServletRequest, and use request.getHeader(something), I get this 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
How do I fix this? I tried using RequestContextHolder, but upon debugging I still see null. How do I use the RequestContextListener when my project has no web.xml.
Request Header can be accessed using HttpServletRequest below way.
private static HttpServletRequest getRequest() {
return((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
}
public static String getApiTraceId() {
return getRequest().getHeader(something);
}
Aspect annotations spins a new thread which is different from the one httpservlet is available in. This is why request was not available within the #ASpect. To resolve it, call the request object BEFORE the aspect method, cache it and call the same method as before.

Save the Spring Security Context back to session for subsequent use

My SpringBoot application is a packaged software application, to customize it I want to manipulate the authentication object when users first login, and I expect this object would be pushed back to the user's session for subsequent connection.
I managed to use an Around advice to intercept a REST endpoint that will be triggered when first login:
#Around("execution( * com.myproject.CurrentUser.get(..)))"
public ResponseEntity getCurrentUser(ProceedingJoinPoint pjp) throws Exception {
SecurityContextHolder.getContext().setAuthentication(getNewAuthentication());
((ServletRequestAttributes) RequestContextController.currentRequestAttributes())
.getRequest().getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING.SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
ResponseEntity response = (ResponseEntity) pjp.proceed();
return response;
}
The getNewAuthentication() method is confirmed OK, it returns a PreAuthenticatedAuthenticationToken that includes additional authorities.
However in the subsequent REST calls when I check the Security Context object the authentication is still the original one.
May I know what would be the proper way to do this? I need to manipulate the authentication object at the very beginning and make sure the subsequent calls will make use of it.
Any idea?

Is it possible to generate a request scope?

I'm using a request scoped bean in my application:
#Bean
#RequestScope
public BeanA beanA(){
return new BeanA();
}
And, as long as I get web requests it is fine.
Problem is that I'm now supporting also other sources of request (for example Spring data redis listener) but, when I want to populate it with values I get
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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Would it possible to create a request scope?

Servlet context and Session in Camel Spring remoting via JMS

I'm trying to integrate 2 spring-mvc applications using Camel-Spring-remoting via JMS/ActiveMQ component.
I'm successfully able to call a remote method in App1 from App2.
App1 and App2 has Shared Web Sessions (using Spring-Session/Redis) which has data like currentUserId and it's properties. The call the session something like below:
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attributes.getRequest().getSession(false);
session.getSession().getAttribute("SYSTEM_USER_ACCOUNT");
Because the remoting method calling is happening via JMS, App1 is not able to identify the previously authenticated HTTP session and I'm getting below exception in App1
org.apache.camel.RuntimeCamelException: java.lang.IllegalStateException: 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.
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1556)
at org.apache.camel.component.bean.BeanInvocation.invoke(BeanInvocation.java:87)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:134)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:448)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:191)
.
.
Caused by: java.lang.IllegalStateException: 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.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at com.keype.hawk.core.api.system.util.SessionUtils.getSession(SessionUtils.java:38)
at com.keype.hawk.core.api.system.util.SessionUtils.getSystemUserAccount(SessionUtils.java:104)
at com.keype.hawk.core.api.system.util.SessionUtils.getStaffId(SessionUtils.java:98)
at com.keype.hawk.core.impl.party.service.PartyServiceImpl.preUpdate(PartyServiceImpl.java:208)
at com.keype.hawk.core.impl.party.service.PartyServiceImpl.updateParty(PartyServiceImpl.java:525)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
What's the practice here ? How can I access the servlet context and current user's http-session from within a JMS call ?

How to get request info on session created in Spring MVC?

I'm hoping to save some client info (IP address, etc) to a database on session created in Spring MVC.
I created a class implementing HttpSessionListener and configured it in web.xml. However, I'm not sure where to go after that.
Would like to be able to inject a bean as well (Spring Data JPA repository).
I've seen How to get the IP address when a session is created? , however if I try to access RequestContextHolder.currentRequestAttributes() I get the following exception:
SEVERE: Session event listener threw exception
java.lang.IllegalStateException: 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.
You can create a bean this way with Spring java config:
#Bean
#Named ("IP")
#Scope ("session")
public String ip (HttpServletRequest request) {
return request.getRemoteAddr ();
}
If all you want to do is log stuff then you should use the HttpSessionListener, please provide your source and full stack trace. Use pastebin.com if necessary.

Resources