Get/set ServletRequest attributes from ActionContext - struts2

I need to set a ServletRequest attribute within a Struts2 interceptor (not action class).
Does the ActionContext expose a Map<String, Object> to control request attributes, like it does for session attributes?
I see ActionContext implements a map. Is the ActionContext itself a wrapper for the request attributes?

The ActionContext contains a request key that holds the request object. To answer you question: no the ActionContext is not a wrapper for request, however the request in Struts2 is a wrapper for the servlet request.
You can get the request from the action context like
HttpServletRequest request = ServletActionContext.getRequest();
That way is useful in interceptors, but in action better to implement ServletRequestAware
protected HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}

For code that is not inside an action class (RequestAware should be used for action classes), Struts2 can expose the servlet request attributes as a Map. They are accessible with:
Map request = (Map) ActionContext.getContext().get("request");
See Strus2 documentation for more details.

Related

HttpServlet is set to null in struts2

I am a newbie for struts. I have a requirement to Migrate from struts1 to struts2 application. I have to pass HttpServlet to one service which was already written in struts1 application. My controller has:
class myController{
HttpServletRequest request;
HttpServlet servlet;
}
where
HttpServletRequest request= org.apache.struts2.dispatcher.StrutsRequestWrapper but HttpServlet servlet = null
Since my service takes servlet as input parameter I am not able to get the output value as servlet is null.
Is there any way in Struts2 to set HttpServlet value? Please suggest.

Access HttpServletRequest from an Authenticator using Dropwizard

Using DropWizard(Jersey Server), Is it possible to access HttpServletRequest from an Authenticator?
I would give it an attribute.
I tried with:
#Context
private HttpServletRequest servletRequest;
But it's not injected.
I registered my Authenticator using:
env.jersey().register(
new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>().setAuthenticator(new FooAuthentificator())
.setRealm("Realm").buildAuthFilter()));
It's possible, but the problem is, the Authenticator never goes through the DI lifecycle, so it never gets a chance to get injected. What we can do though is explicitly inject it ourselves. To do that, we need to get a hold of the ServiceLocator (which is the main IoC container, kind of like ApplicationContext with Spring). Once we have the ServiceLocator, we can call locator.inject(anyObject) to explicitly resolve any injection dependencies.
The easiest place to get the ServiceLocator, when configuring the app, is in a Feature. Here we can also register Jersey components. Calling register on the FeatureContext (seen below) is just like calling env.jersey().register(...) with Dropwizard, it has the same effect. So we can do
public class AuthenticatorFeature implements Feature {
#Override
public boolean configure(FeatureContext ctx) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(ctx);
TestAuthenticator authenticator = new TestAuthenticator();
locator.inject(authenticator);
ctx.register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(authenticator)
.setRealm("SEC REALM")
.buildAuthFilter()));
ctx.register(new AuthValueFactoryProvider.Binder<>(User.class));
return true;
}
}
You can see that explicitly inject the authenticator, with the call to locator.inject(authenticator). Then we register this feature through Dropwizard
env.jersey().register(new AuthenticatorFeature());
Tested, and works fine.
Note, if you are wondering how it's possible to inject the HttpServletRequest, when there is no current request, it's because a proxy is injected. Same thing as if you were to inject the request into a Jersey filter, the same thing happens; a proxy is injected, as there is only a singleton filter, but the request changes from request to request, so a proxy needs to be injected.
See Also:
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey

Spring 3, Spring Security. Extract authenticated User object

This is a Spring Security question.
In my application, I have a User entity as a domain object. This object contains implementation to support Spring UserDetails object. The authentication (login/logout) process works fine.
The challenge is that I need to extract that object from the session to make 'business logic' decisions in my code.
I've been reading about querying SecurityContextHolder, but frankly, I still don't know what is the best approach, given that multiple Spring versions seem to be a factor in those discussions. Also, the Principal object isn't a solution for me, as it does not seem to contain any access level or role information.
Below is a simple controller to illustrate my challenge. It has my User domain object hardcoded. I need to replace that block with code that will obtain the User object from Spring Security session. I'm looking for the best way to do this within Spring 3.
Can I get this object as my domain object or do I need to get it as Spring UserDetails object and manually convert it?
Can this Security context lookup be injected somehow into my controller?
public class HomeController {
#RequestMapping(value="/home.html", method=RequestMethod.GET)
public ModelAndView getHomePage(Map<String, Object> model) {
// Get current user
User currentUser=new User();
currentUser.setUserName("Admin");
currentUser.setAccessLevel(UserAccessLevel.ADMINISTRATOR);
// Construct HomePage bean
HomeBean bean=new HomeBean();
bean.setCurrentUserName(currentUser.getUserName());
// Construct list of catalogs
Collection<String> catalogList=new ArrayList<String>();
catalogList.add("articles");
catalogList.add("files");
catalogList.add("comments");
if(currentUser.hasAdministratorAccessLevel()) {
catalogList.add("users");
}
bean.setCatalogList(catalogList);
// Construct and return ModelAndView
ModelAndView mav=new ModelAndView();
mav.setViewName(WebView.HOME_PAGE.getViewName());
mav.addObject(bean.getBeanId(), bean);
return mav;
}
=== Update 2012-01-07 ======================================================
I'm working with Luke's suggestion. The method that gets UserDetails from session and converts it to a returned my domain User object is in my UserService.
Here's my controller:
#Controller
public class HomeController {
#Autowired
private UserService userService;
#RequestMapping(value="/home.html", method=RequestMethod.GET)
public ModelAndView getHomePage(Map<String, Object> model) {
// Construct HomePage bean
HomeBean bean=new HomeBean();
User currentUser=userService.getCurrentlyAuthenticatedUser();
bean.setCurrentUserName(currentUser.getUserName());
And here's key code from UserServiceImpl.getCurrentlyAuthenticatedUser():
#Override
public User getCurrentlyAuthenticatedUser() {
User currentUser=new User();
Authentication a = SecurityContextHolder.getContext().getAuthentication();
UserDetails currentUserDetails = (UserDetails) a.getPrincipal();
if(currentUserDetails==null) {
return currentUser;
}
currentUser.setUserName(currentUserDetails.getUsername());
This works but am I doing this right? Feedback much appreciated. I am still unable to retrieve my User domain object from the session. I'm retrieving Spring's UserDetails object and with it constructing my domain User object but in the process some information is lost.
Normally, the principal object contained in the successful Authentication will be an instance of your user object. So, for a quick solution, use
Authentication a = SecurityContextHolder.getContext().getAuthentication();
User currentUser = (User)a.getPrincipal();
But also (once you get that working), you might want to look at the answer I just gave (to a similar question) on how to inject a custom security context accessor.
Spring also provides an annotation #AuthenticationPrincipal, it is used to resolve Authentication.getPrincipal(). It can be used like below...
public ResponseEntity<UserProfileResponse>UserProfile(#AuthenticationPrincipal JwtAuthenticationToken principal){

How to call Backing Bean method to fetch the request Header value from Incoming request and forward result to a JSF page

My requirement is " Our users are Authenticated by External System using SSO".
On successful authentication the external system returns header variables viz. userId,
firstName, lastName etc to our System.
Currently I am able to retrieve these header variables using
request.getHeader("userId") in my JSP page.
But I am using JSF 2.0 and not able to figure out as to how this can be done in JSF. I saw one example here on Stack overflow ...
Map<String, String> requestHeaders = context.getExternalContext().getRequestHeaderMap();
String userName = requestHeaders.get(requestHeaderName);
but there was no further response as how this will be invoked on the backing bean.
Any pointer or sample code would be helpful.
The context is here just the current instance of the FacesContext. This is a request based threadlocal variable which is always available throughout all the JSF code which is controlled by the FacesServlet.
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> requestHeaders = context.getExternalContext().getRequestHeaderMap();
String userName = requestHeaders.get(requestHeaderName);
// ...
You can invoke this in for example the bean's constructor, the bean's #PostConstruct method, the bean's action(listener) method, etcetera. The right place depends on the moment you want to collect this information and what you want to do with this information.

how to decouple controller from Http context session

I need to store some data in session inside my action however I'm concerned about coupling my controller to the http context session, I have thought about creating a service, but is it really worth it?
No, it isn't worth it. It is the controller that has access to the Http Context including the session. Not to mention that you already are working with an abstraction of the session: HttpSessionStateBase which can be easily mocked in a unit test.
There might be situations where you could have your business methods take ICollection as input parameter which is an interface implemented by HttpSessionStateBase and then have the controller pass the Session object to them.
Especially for ApiControllers, build yourself a DelegatingHandler and push all of your goodies onto request.Properties. You can then retrieve them from your request whether you are testing or running live. The benefit is that you then have zero dependency on Session in your Controller.
MessageHandler
public class ContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
// get the goodies to add onto the request
var goodies = /* call to goodieGoodieYumYum */
// add our goodies onto the request
request.Properties.Add(Constants.RequestKey_Goodies, goodies);
// pass along to the next handler
return base.SendAsync(request, cancellationToken);
}
}
Controller Action
var goodies = (List<Goodie>)Request.Properties[Constants.RequestKey_Goodies];

Resources