At which point can I add custom information into userDetails? - spring-security

I want to store additional information in my custom "userDetail"-object, but I am not sure when I want to add the information into the object. It needs to be accessible for every method after the login happened (JWT-Token login) via SecurityContextHolder.getContext().getAuthentication().getInformation()
I thought about setting it in my custom AuthenticationController around the time the token is generated, but this is difficult due to the act that the referenced type at that point is userDetails, not customUserDetails:
UserDetails userDetails = this.userDetailsService.loadUserByUsername(authenticationRequest.getUsername());
//TODO setInformation
String token = this.tokenUtils.generateToken(userDetails);
What is the best point in the authentication/authorization process to add such information, and how would I best do so?

After further research, the best point in time to populate the user object with custom data seems to be the constructor of your customized implementation of the UserDetails interface, at the same time Authorities and other data is set for the User object. For example:
public SpringSecurityUser(Long id, String username, String password, String email, Date lastPasswordReset,
Collection<? extends GrantedAuthority> authorities) {
this.setId(id);
this.setUsername(username);
this.setPassword(password);
this.setEmail(email);
this.setLastPasswordReset(lastPasswordReset);
this.setAuthorities(authorities);
this.setMyInfo(Information);
}
This was initially a problem for me, because the method setting the information was doing so based on the logged in Principal, which is not possible because at that time of the login process, the Principal is being created.

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
}

Spring Security - Invalid property 'principal' of bean class [org.springframework.security.authentication.UsernamePasswordAuthenticationToken]

I had to implement a custom "authentication provider" for a project, but I ran into troubles when trying to acces the Authentication's object properties in JSP. Details:
My custom authentication provider successfully creates an Authentication object
Authentication auth = new UsernamePasswordAuthenticationToken(username, password, getAuthorities(userRoles));
log.info("User is authenticated");
return auth;
(Only relevant code here)
Then, in the controller method, I just display a log message with the username (this proves that the Authentication object is created and placed in the security context):
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
log.info("Welcoming user " + auth.getPrincipal());
Then in the JSP page I want to display the user name using
<sec:authentication property="principal"/>
However, this raises an error 500:
org.springframework.beans.NotReadablePropertyException: Invalid property 'principal' of bean class [org.springframework.security.authentication.UsernamePasswordAuthenticationToken]: Bean property 'principal' is not readable...
I also noticed that
<sec:authorize ifAnyGranted="role">...
is not working, although the user has the necessary roles added in the Authentication object.
Is there something I'm doing wrong? The authentication works fine, I just can't access the authentication object's properties.
Thank you very much and have a good day.
your AuthenticationProvider must return UserDetails object.
From spring documentation
This tag allows access to the current Authentication object stored in the security context. It renders a property of the object directly in the JSP. So, for example, if the principal property of the Authentication is an instance of Spring Security's UserDetails object, then using will render the name of the current user.
Given that I can't see anything wrong with your case, I think it can be SPR-8347 bug, which is fixed in Spring 3.1.1. Can you do an upgrade?
Old question, but I think that I can help other folks.
As the first parameter of UsernamePasswordAuthenticationToken you may send a User.
Instead of passing the username, pass the user itself. But the user must be a class that extends org.springframework.security.core.userdetails.UserDetails:
Authentication auth = new UsernamePasswordAuthenticationToken(user, password, getAuthorities(userRoles));
log.info("User is authenticated");
return auth;
See the method that you was using:
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}
Now, in yout tamplete, um can use something like this:
<span class="hidden-sm-down" sec:authentication="principal.email">Email</span>

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 might a site like Stack Overflow pass user information around in ASP.NET MVC?

Basically, I log into my website using OpenId, very similar to what I am assuming SO does. When I get the information back, I throw it into a database and create my "Registered User". I set my AuthCookie:
FormsAuthentication.SetAuthCookie(user.Profile.MyProfile.DisplayName, false);
Then I can use this for the User Name. However, I would like to pass in the entire object instead of just the string for display name. So my question is:
How does SO do it?
Do they extend/override the SetAuthCookie(string, bool) method to accept the User object, i.e. SetAuthCookie(User(object), bool).
What is the best way to persist a User object so that it is available to my UserControl on every single page of my Web Application?
Thanks in advance!
You can achieve this behavior by implementing your custom Membership Provider, or extending an existing one. The provider stores user information based on a key (or just by user name) and provides access to the MembershipUser class, which you can extend however you wish. So when you call FormsAuthentication.SetAuthCookie(...), you basically set the user key, which can be accessed be the provider.
When you call Membership.GetUser(), the membership infrastructure will invoke the underlying provider and call its GetUser(...) method providing it with a key of the current user. Thus you will receive the current user object.
Jeff,
As I said in a comment to your question above, you must use the ClaimedIdentifier for the username -- that is, the first parameter to SetAuthCookie. There is a huge security reason for this. Feel free to start a thread on dotnetopenid#googlegroups.com if you'd like to understand more about the reasons.
Now regarding your question about an entire user object... if you wanted to send that down as a cookie, you'd have to serialize your user object as a string, then you'd HAVE TO sign it in some way to protect against user tampering. You might also want to encrypt it. Blah blah, it's a lot of work, and you'd end up with a large cookie going back and forth with every web request which you don't want.
What I do on my apps to solve the problem you state is add a static property to my Global.asax.cs file called CurrentUser. Like this:
public static User CurrentUser {
get {
User user = HttpContext.Current.Items["CurrentUser"] as User;
if (user == null && HttpContext.Current.User.Identity.IsAuthenticated) {
user = Database.LookupUserByClaimedIdentifier(HttpContext.Current.User.Identity.Name);
HttpContext.Current.Items["CurrentUser"] = user;
}
return user;
}
}
Notice I cache the result in the HttpContext.Current.Items dictionary, which is specific to a single HTTP request, and keeps the user fetch down to a single hit -- and only fetches it the first time if a page actually wants the CurrentUser information.
So a page can easily get current logged in user information like this:
User user = Global.CurrentUser;
if (user != null) { // unnecessary check if this is a page that users must be authenticated to access
int age = user.Age; // whatever you need here
}
One way is to inject into your controller a class that is responsible for retrieving information for the current logged in user. Here is how I did it. I created a class called WebUserSession which implements an interface called IUserSession. Then I just use dependency injection to inject it into the controller when the controller instance is created. I implemented a method on my interface called, GetCurrentUser which will return a User object that I can then use in my actions if needed, by passing it to the view.
using System.Security.Principal;
using System.Web;
public interface IUserSession
{
User GetCurrentUser();
}
public class WebUserSession : IUserSession
{
public User GetCurrentUser()
{
IIdentity identity = HttpContext.Current.User.Identity;
if (!identity.IsAuthenticated)
{
return null;
}
User currentUser = // logic to grab user by identity.Name;
return currentUser;
}
}
public class SomeController : Controller
{
private readonly IUserSession _userSession;
public SomeController(IUserSession userSession)
{
_userSession = userSession;
}
public ActionResult Index()
{
User user = _userSession.GetCurrentUser();
return View(user);
}
}
As you can see, you will now have access to retrieve the user if needed. Of course you can change the GetCurrentUser method to first look into the session or some other means if you want to, so you're not going to the database all the time.

asp.net mvc authentication against shibboleth and authorization

Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.

Resources