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
}
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
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.
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();
}
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.