Struts 2 Session in interceptor - struts2

I am trying to access session object from within my interceptor by implementing SessionAware interface (I've implemented the setSession method), but I am not able to get my session object this way.
Then I tried ActionContext.getContext().getSession() and I am able to get the session, but I don't know but its coming out to be empty for only the first time in every browser for every user & then it comes filled when another action is invoked.
I assume there is something wrong going with the session. Why is it giving me an empty session only for the first time? Does it set something only after giving empty session for the first time?
If this is the case then everyone will be shown as guest on their first request & then with a username on their 2nd request & hence forth.
Or am I getting the session in the wrong way?
I saw code to get sessions in interceptors, but this does not work for me as it cannot find the constant HTTP_REQUEST.
final ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
HttpSession session = request.getSession(true);
Object user = session.getAttribute(Constants.USER_HANDLE);
Any suggestion on resolving any of the problems?
Something I forgot to mention - my website is a secure site(https), so if the user is not logged in, it would not let him enter the website & if he is logged in, at least his username should be there in the session. Shouldn't it be?

I have an interceptor that also grabs the session as a map. Have you tried something like this? This works for me.
public String intercept( ActionInvocation actionInvocation ) throws Exception {
Map session = actionInvocation.getInvocationContext().getSession();

You can use the following to return the HttpSession -- and create it if it doesn't exist.
HttpSession session = ServletActionContext.getRequest().getSession(true);
If you need the Map instead, then you can just call this right after that last call (since you passed true, the session would have been created and the next call will return a blank session map).
Map<String, Object> session = ActionContext.getContext().getSession();
Alternatively, you can use the CreateSessionInterceptor early in your stack so that the session is created by the time you need it. Then just use the map example above to get it.
FYI: ServletActionContext is a subclass of ActionContext that just has convenience methods for getting the request and response without needing to use the constants like you were trying in your example.

Try this. It worked for me in struts 2.0.14.
public String intercept(ActionInvocation ai) throws Exception {
Map session = ActionContext.getContext().getSession();

You can get the session on Interceptor using ActionContext itself...refer the following code snippet:
SessionMap<String, Object> session = ActionContext.getContext().getSession();
or alternatively you can follow this approach:
The request is available on the ActionContext instance, which is made available via ThreadLocal.
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession(true);

Add the import:
import org.apache.struts2.StrutsStatics;

Related

How to get the currently logged in CustomUser object

So i am trying to figure out if there is a simpler and more straightforward way of obtaining a CustomUser object for the currently logged in user.
I have a custom UserServiceImplementation and use a Custom User object.
Reading around i noticed the use of #AuthenticationPrincipal but i cannot seem to get any examples of it working. Furthermore it depends on #EnableWebMVCSecurity which is depreciated for the current version of spring security that i am using (4.x.x).
Am i looking at the right functionality to be able to achieve my goal or should i be looking at something completely different?
Example of my current code where i am forced to get current user object for the logged in user to be able to achieve further processing.
#RequestMapping(value = "/map", method = method = RequestMethod.POST)
public String processMap(#Valid MapProc mapObject) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = userInterface.findByLogin(((UserDetails) principal).getUsername());
// rest of code
return "map/processed";
}
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userName= auth.getName();
In the Session is always the UserDetails object from the UserDetailsService persistent. If you have your own Implementation witch returns your own User Object you get it by:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof User) {
//Your Code here
}

How to clear an object of the session scoped managed bean?

I am developing a login based application in JSF with primefaces. In that I kept the logged user info in session scoped managedbean and I need to clear that details when he logged out, So How to clear those details which are in SessionScoped ManagedBean object?
You need to invalidate the current session by calling the following function in your action method:
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
Also, as the session scoped beans are trashed buring the subsequent request, be sure to send a redirect:
FacesContext.getCurrentInstance().getExternalContext().redirect("/login.xhtml");
Or, simply return a navigation case outcome from your method:
return "login.xhtml?faces-redirect=true";
In case you don't want to invalidate the session and, effectively, retaining your session scoped beans (which is a bad practice in my opinion), just nullify all of the user data (which was hopefully collected in one session scoped managed bean) in the logout method (you may need to inject that bean in case the logout method resides in another session scoped bean).
You don't need to clear session scoped managed bean manually. Just clear the user session.
By using following code in servlet for logout.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
System_Properties system_Properties=new System_Properties();
PrintWriter out = response.getWriter();
try {
request.getSession().invalidate();
}finally {
out.close();
}
}
If you still manually clear the managed bean data then it can be done by using following code.
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("managed_bean_name", null);
Where "mananged_bean_name" is name of your managed bean.
Hope it helps
When the user logout, the session is destroyed and all the SessionScoped ManagedBean objects too

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.

Using ASP .NET Membership and Profile with MVC, how can I create a user and set it to HttpContext.Current.User?

I implemented a custom Profile object in code as described by Joel here:
How to assign Profile values?
I can't get it to work when I'm creating a new user, however. When I do this:
Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyRole");
the user is created and added to a role in the database, but HttpContext.Current.User is still empty, and Membership.GetUser() returns null, so this (from Joel's code) doesn't work:
static public AccountProfile CurrentUser
{
get { return (AccountProfile)
(ProfileBase.Create(Membership.GetUser().UserName)); }
}
AccountProfile.CurrentUser.FullName = "Snoopy";
I've tried calling Membership.GetUser(userName) and setting Profile properties that way, but the set properties remain empty, and calling AccountProfile.CurrentUser(userName).Save() doesn't put anything in the database. I've also tried indicating that the user is valid & logged in, by calling Membership.ValidateUser, FormsAuthentication.SetAuthCookie, etc., but the current user is still null or anonymous (depending on the state of my browser cookies).
SOLVED (EDITED FURTHER, SEE BELOW): Based on Franci Penov's explanation and some more experimentation, I figured out the issue. Joel's code and the variations I tried will only work with an existing Profile. If no Profile exists, ProfileBase.Create(userName) will return a new empty object every time it's called; you can set properties, but they won't "stick" because a new instance is returned every time you access it. Setting HttpContext.Current.User to a new GenericPrincipal will give you a User object, but not a Profile object, and ProfileBase.Create(userName) and HttpContext.Current.Profile will still point to new, empty objects.
If you want to create a Profile for a newly-created User in the same request, you need to call HttpContext.Current.Profile.Initialize(userName, true). You can then populate the initialized profile and save it, and it will be accessible on future requests by name, so Joel's code will work. I am only using HttpContext.Current.Profile internally, when I need to create/access the Profile immediately upon creation. On any other requests, I use ProfileBase.Create(userName), and I've exposed only that version as public.
Note that Franci is correct: If you are willing to create the User (and Roles) and set it as Authenticated on the first round-trip, and ask the user to then log in, you will be able to access the Profile much more simply via Joel's code on the subsequent request. What threw me is that Roles is immediately accessible upon user creation without any initialization, but Profile is not.
My new AccountProfile code:
public static AccountProfile CurrentUser
{
get
{
if (Membership.GetUser() != null)
return ProfileBase.Create(Membership.GetUser().UserName) as AccountProfile;
else
return null;
}
}
internal static AccountProfile NewUser
{
get { return System.Web.HttpContext.Current.Profile as AccountProfile; }
}
New user creation:
MembershipUser user = Membership.CreateUser(userName, password);
Roles.AddUserToRole(userName, "MyBasicUserRole");
AccountProfile.NewUser.Initialize(userName, true);
AccountProfile.NewUser.FullName = "Snoopy";
AccountProfile.NewUser.Save();
Subsequent access:
if (Membership.ValidateUser(userName, password))
{
string name = AccountProfile.CurrentUser.FullName;
}
Further thanks to Franci for explaining the Authentication life cycle - I'm calling FormsAuthentication.SetAuthCookie in my validation function, but I'm returning a bool to indicate success, because User.Identity.IsAuthenticated will not be true until the subsequent request.
REVISED: I'm an idiot. The above explanation works in the narrow case, but doesn't resolve the core problem: Calling CurrentUser returns a new instance of the object each time, whether it's an existing Profile or not. Because it's defined as a property, I wasn't thinking about this, and wrote:
AccountProfile.CurrentUser.FullName = "Snoopy";
AccountProfile.CurrentUser.OtherProperty = "ABC";
AccountProfile.CurrentUser.Save();
which (of course) doesn't work. It should be:
AccountProfile currentProfile = AccountProfile.CurrentUser;
currentProfile.FullName = "Snoopy";
currentProfile.OtherProperty = "ABC";
currentProfile.Save();
It's my own fault for completely overlooking this basic point, but I do think declaring CurrentUser as a property implies that it's an object that can be manipulated. Instead, it should be declared as GetCurrentUser().
Creating a user just adds it to the list of users. However, this does not authenticate or authorize the new user for the current request. You also need to authenticate the user in the current request context or for subsequent requests.
Membership.ValidateUser will only validate the credentials, but it's not authenticating the user for the current or subsequent requests. FormsAuthentication.SetAuthCookie will set the authentication ticket in the response stream, so the next request will be authenticated, but it does not affect the state of the current request.
The easiest way to authenticate the user would be to call FormsAuthentication.RedirectFromLoginPage (assuming you are using forms authentication in your app). However, this one would actually cause a new HTTP request, which will authenticate the user.
Alternatively, if you need to continue your logic for processing the current request, but want the user to be authenticated, you can create a GenericPrincipal, assign it the identity of the new user and set the HttpContext.User to that principal.
You are going to run into problems with this approach if you enable anonymousIdentification. Rather than Membership.GetUser().UserName, I would suggest using HttpContext.Profile.UserName.
Like this...
private UserProfile _profile;
private UserProfile Profile
{
get { return _profile ?? (_profile = (UserProfile)ProfileBase.Create(HttpContext.Profile.UserName)); }
}
Hat tip: SqlProfileProvider - can you use Profile.GetProfile() in a project?
First of all, thanks #Jeremy for sharing your findings. You helped me get going in the right direction. Secondly, sorry for bumping this old post. Hopefully this will help someone connect the dots.
The way I finally got this working was to use the following static method inside my profile class:
internal static void InitializeNewMerchant(string username, Merchant merchant)
{
var profile = System.Web.HttpContext.Current.Profile as MerchantProfile;
profile.Initialize(username, true);
profile.MerchantId = merchant.MerchantId;
profile.Save();
}

asp.net mvc - need to store some data for the current request

I am writing a user authentication class. During the request there are a lot of references to the current user, so I would like to cache it in memory instead of calling the database ala singleton. I am thinking about using session and clearing it at the end of every request.
like:
public static User Current() {
if (Session["current-user"] == null) {
Session["current-user"] = GetUserFromDB(); // example function, not real
}
return (User)Session["current-user"];
then in app_end request:
Session.Clear();
HttpContext.Items["user"] = user;
You can reference the context items during the entire request and it will be cleaned up at the end of it.
Use the HttpContext class. You can get to it either in the context of a controller of HttpContext.Current.
The HttpContext.Items collection is what you want to use.

Resources