when loadUserByUsername is invoked? (spring security) - java

I'm learning Spring Security and I have few quick questions respect UserDetailsService:
1- When loadUserByUsername is actually called or invoked? After authentication? Only once per login?
2- After login, will Spring put the actual logged user into httpSession?
3- Which is the recommended way to populate the collection of <GrantedAuthority> of UserDetails?
Eagle fetch them so when loadUserByUsername is called, the returned user already has it's "ROLES"
Implement another custom filter like UsernamePasswordAuthenticationFilter populate after success login?
Neither of aboveā€¦

It is typically called by an AuthenticationProvider instance in order to authenticate a user. For example, when a username and password is submitted, a UserdetailsService is called to find the password for that user to see if it is correct. It will also typically provide some other information about the user, such as the authorities and any custom fields you may want to access for a logged in user (email, for instance). That is the main usage pattern. You can grep the code to see exactly where it is called.
As explained in the manual:
There is often some confusion about UserDetailsService. It is purely a DAO for user data and performs no other function other than to supply that data to other components within the framework. In particular, it does not authenticate the user, which is done by the AuthenticationManager. In many cases it makes more sense to implement AuthenticationProvider directly if you require a custom authentication process.
Yes. A SecurityContext instance is stored in the session once the user has been authenticated.
If you need to implement a custom UserDetailsService then it will depend on your requirements and how they are stored. Typically you would load them at the same time as the other user information. It's not something you would likely do in a filter. As explained in the above quotation from the manual, if you are actually implementing a different authentication mechanism then you should implement AuthenticationProvider directly. It isn't compulsory to have a UserDetailsService in your app. You can think of it as a strategy that is used by certain built-in features.

Related

Retrieve not-logged User Details from Spring Security

I know how to retrieve user details if he is logged on, using SecurityContextHolder.
// Some code
UserDetails userDetails =
(UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
So, my question is:
Is it possible to retrieve information about not currently logged user, for example by User Id only?
And how can I update the information about users if they are currently offline?
The one populating your SecurityContext is usually a UserDetailsService, which you have to implement yourself or you take one of the existing ones.
I'm not sure I fully understand your question, but in theory you can simply use your UserDetailsService (or the services it itself uses to load a user), to get all the details you want. So, if you have a JPAUserDetailsService, this will likely call a repository and there's nothing stopping you from using that repository yourself.
What exactly is it that you are trying to do?

Spring Security -- Retrieving the Username of the user currently trying to log in

I need to implement a PasswordEncoder that generates salted passwords. The salts are user-specific (UUIDs) and stored in the corresponding User objects.
As such, I need access to either the User directly or the UserDetails object that holds a reference. Very easy to retrieve IF I had the name of the user trying to log in.
And therein lies the issue. I cannot seem to get a hold of it.
As far as the SecurityContext is concerned, we are still dealing with an anonymousUser.
I know there should be a UsernamePasswordAuthenticationToken lying around, somewhere, but I cannot inject that as it's not a bean. And to define a wrapper bean holding it, I would need to figure out where to find it in the first place.
How do I get the name of the user trying to log in?
Would greatly appreciate the help. :)
(Sidenote: Please don't recommend me to "not do that" or to migrate the passwords and start using a BCryptPasswordEncoder or something along these lines. It's something we would very much like to do at some point in the future but for the time being are not allowed to.)
You won't be able to do this with a PasswordEncoder alone as the abstraction assumes that you can encode the password using only the plain text password (or compare using the hashed password). However, if you use a custom AuthenticationProvider (which is what calls the PasswordEncoder), you will have access to the incoming Authentication object including the username. More info here.
The call to PasswordEncoder.matches(...) is made by the additionalAuthenticationChecks(...) method of DaoAuthenticationProvider, which does have access to the username value (principal).
If you need access to that, you need to subclass DaoAuthenticationProvider and override (replace) the method, and make sure Spring uses your subclass when configuring.

User Principal in JAAS Login Module - extra attributes as separate Principal or as Bean properties?

I've implemented a JAAS LoginModule that is working great with Spring 4 and Struts 2.3. This same LoginModule is also invoked via a ServletFilter in Tomcat 8.0/8.5 to authenticate and authorize requests to Servlets outside of the Spring framework.
The LoginModule uses a simple implementation of java.security.acl.Group and separates the User(s) and Role(s) with two simple implementations of java.security.Principal. By "simple" I mean the minimal implementations that satisfy the interfaces.
The "User" implementation maps the name property to a unique username (actually an e-mail address). Since the e-mail address is unique but could change, the account database contains a unique account identifier (GUID) that is used to assign groups, roles and to log service requests (while also anonymizing our users). In my model, the AccountIdentifier has its own class. Essentially, I have two unique identifiers for accounts, but since the e-mail address needs to be supplied to the LoginModule for authentication, it ended up being the basis for the User principal.
The account identifier is not currently being propagated through to the Subject in the LoginModule, but now I need it in order to log service requests.
I see two ways forward with making the account identifier available via the Subject, but I am uncertain which is the best practice for JAAS:
Extend my current "User" Principal implementation to include an "accountIdentifier" property that is set during LoginModule.commit().
Implement AccountIdentifier as a separate Principal that gets added to the Subject during the LoginModule.commit().
The first option would be easiest, but that also seems like it defeats the purpose of segregating Personally Identifying Information from accounts (which is something I need to do in order to satisfy the upcoming European GDPR requirements).
Should I even be adding the "User" principal (the one that contains the e-mail address) to the Subject?
There are several incompatibilities among the JAAS and Servlet specifications regarding authentication and user principles. Because of this, Spring uses a different approach to JAAS integration than Tomcat.
This answer documents a comprehensive method of implementing JAAS Login Modules in a way that accommodates both Tomcat and Spring.
For clarity, the two options for implementing user principles is copied here from the question:
Extend my current "User" Principal implementation to include an "accountIdentifier" property that is set during LoginModule.commit().
Implement AccountIdentifier as a separate Principal that gets added to the Subject during the LoginModule.commit().
Option 1 has the unfortunate side affect of joining together different forms of Personally Identifiable Information, which in some environments could violate the European GDPR regulations (sessions may be serialized onto disk, and this information would go with it).
Option 2 separates out Personally Identifiable Information, but must be implemented in a way that overcomes several limitations in the Servlet Specification and Tomcat's JAAS implementation.
These limitations are described in detail below, with the bold sections summarizing the main points.
JAASRealm requires that the backing collection(s) of a Subject preserve the ordering of the Principals.
The Tomcat 8.5 JAAS Realm documentation states:
Using JAASRealm gives the developer the ability to combine practically
any conceivable security realm with Tomcat's CMA.
but then goes on to state:
Although not specified in JAAS, you should create separate classes to
distinguish between users and roles, extending javax.security.Principal
so that Tomcat can tell which Principals returned from your login module
are users and which are roles (see org.apache.catalina.realm.JAASRealm).
Regardless, the first Principal returned is always treated as the user
Principal.
Note that the above Tomcat documentation uses the phrase "the user Principal". Although the JAAS API recommends implementing users and roles as distinct classes extending javax.security.Principal, this is not compatible with the Servlet Specification because HttpServletRequest.getUserPrincipal() allows only for a single Principal to be returned:
Returns a javax.security.Principal object containing the name of the
current authenticated user. If the user has not been authenticated,
the method returns null.
A strict reading of the above documentation states that it should contain "...the name of the current authenticated user", but in order to satisfy my original goal, I am interpreting this as "...any name or identifier for the authenticated Subject". This corresponds more closely to the com.sun.security.auth.UserPrincipal documentation (i.e., "A user principal identified by a username or account name").
Due to the above limitations in Tomcat's JAASRealm and the Servlet Specification's HttpServletRequest, it is clearly important that if the account identifier is to be propagated to the request via a ServletFilter (which only has access to the current session, request and response), it must be contained in the first Principal (thus Option 1 in the original question would satisfy this requirement, or Option 2 only if it appears first and I do not need the original username). I believe all I really need is the account identifier, so I am sticking with the second option for now, where I hand an "EmailAddressPrincipal" to MyLoginModule and I receive an "AccountIdentifierPrincipal" back via the Subject (i.e., the MyLogin.commit() adds the "AccountIdentifierPrincipal" as the very first principal).
The JAASRealm documentation is actually slightly contradictory regarding the precise order of Principals, it depends on which section you're reading:
As this Realm iterates over the Principals returned by
Subject.getPrincipals(), it will identify the first Principal that
matches the "user classes" list as the Principal for this user
vs.
Regardless, the first Principal returned is always treated as the user
Principal.
The Servlet API provides no guarantees of the ordering of Principles returned by a Subject.
Essentially, if I were to create a ServletFilter that mimics what JAASRealm is doing, the authentication would look like this (note the iterator in particular):
final LoginContext loginContext = new LoginContext(MyLoginModule.JAAS_REALM, new DefaultCallbackHandler(username, password));
loginContext.login();
final Subject subject = loginContext.getSubject();
request.getSession().setAttribute("AUTH_USER_PRINCIPAL", subject.getPrincipals(AccountIdentifierPrincipal.class).iterator().next());
request.getSession().setAttribute("AUTH_ROLE_PRINCIPALS", subject.getPrincipals(MyRolePrincipal.class));
Unfortunately, this is in direct conflict with the constructor for javax.security.auth.Subject, which mandates that a java.util.Set is used as the backing collection for Principals. Additionally, the Set.iterator() documentation states:
The elements are returned in no particular order (unless this set is
an instance of some class that provides a guarantee).
The earliest access we have to the Subject is in the LoginModule.initialize() method, which is something that is unfortunately invoked somewhere in the internals of LoginContext (I think). This means we have no control over the exact subclass of Set that is used as the backing collection for Principals, and therefore no control over their ordering. By the time this arrives to the ServletFilter, it is a SynchronizedSet, so it isn't even clear what the original class was, or whether re-ordering occurred.
This all indicates that in order for JAASRealm to work as expected only a single user principal can be provided. There is no interface anywhere in that middle layer that clearly establishes the order of the Subject Principals.
Conclusions
When using JAASRealm, only one Principal of the declared User type should be added to the Subject during commit.
When using JAASRealm, avoid using multiple User class names.
Violating the above two rules may lead to undefined and/or inconsistent behavior.
Solution: Use an AuthorityGranter for Spring, and a ServletFilter for non-framework Tomcat servlets
For the sake of Option 2, I'm avoiding the use of JAASRealm because according to all of the above documentation, it does not faithfully adhere to JAAS. This brings me back to the pure ServletFilter approach.
The javax.security.auth.Subject contains everything needed for authorization: multiple user principals, roles and ACL groups. Unfortunately, this class is only partially serializable, which means I can't just wrap the class as a Principal and return it.
In order to satisfy Spring's DefaultJaasAuthenticationProvider, implement an AuthorityGranter to map Principals to role names - that provides complete control over how the mapping is performed.
Since AuthorityGranter isn't available outside the Spring Framework, I also implemented a ServletFilter that uses a similar approach to map roles for my non-Spring webapp. Temporarily, I am using an HttpServletRequestWrapper to read the Principal and Roles from session attributes (stored in session during authentication) and override getUserPrincipal and isUserInRole. Ultimately, I will revisit JAASRealm to see if it contains any functionality for handling this piece, but I'm not quite there yet.

Spring 3.2 Security - Login with non-unique username and additional info

The title tries to explain the scenario:
This customer has a login functionality that allows users with the same name but on different locations (stores).
At the login page the user informs userName, password and the required store.
Using Spring Security (with JPA) I created an UserDetailsService implementation but this interface always receive an userName (and the store was essential to differ from another users).
Giving this situation I have two questions:
How do I inform the spring security about the additional field? (store)
How do I implement an UserDetailsService with this info?
Is that even possible? I've been doing some research but the solutions weren't clear.
Thank you guys, you are the best =D
Your question is not all clear to me. Do you have a unique login for multiple stores? Then you don't need to give the store to your UserDetailsService implementation. I would simply load the user information using its username and if the users are not authorized for all the stores, you could use the GrantedAuthority to define where the users is authorized, e.g. ROLE_STORE_ID1, ROLE_STORE_ID2, etc.
If you have multiple stores where users are not shared, then you could simply create a configurable custom implementation of UserDetailsService, instantiate one per store and uses the correct instance depending on the store the user is accessing.
I hope this will help.

JBoss Authentication Question(s)

I have a three-part question related to JBoss 5 Authentication (in the Web/EJB containers):
Is there a way to propogate an
identity other than the username
that was specified during login? For
example, using the
DatabaseServerLoginModule, I want to
authenticate the user with a
username/password but return the
user's id, and not username, when
ejbContext.getCallerPrincipal() or
httpRequest.getUserPrincipal() is
called.
Even better, I want to make a custom
login module which returns a User
object (probably an entity which was
loaded from the database). However,
even if I wrap that User object up
nicely in a Principal subclass in my
login module, the EJB-layer never
gets that object. Instead, the
EJB-layer always gets a
SimplePrincipal when
getCallerPrincipal is called.
I want to be able to trigger a login
programmatically, as described in
WebAuthentication. However, I need
to do this without knowing the
password. Imagine a customer service
interface where a customer service
agent can login to the application
as an end-user. They would click a
"login-as" button and we should be
able to programmatically log them in
as a user, without ever knowing the
user's password (the customer
service agent is already
authenticated himself). You could
also have this same scenario with
"forgot password" which uses an
alternate login mechanism to
authenticate the user and then
programatically logs them in.
Thanks!
1) Not that familiar with the DatabaseServerLoginModule but shouldn't the user's id also be their username? Usernames should be unique at least?
(Well after reading the rest of your question maybe this is not helpful...)
Answering my own question from two years ago: since the time I wrote this question, we've switched over to Spring Security and found it to be much more flexible than what's available in JBoss alone. My recommendation to anyone looking for a real solution to this problem is to give up on the container-provided authentication and take a good look at Spring Security.

Categories