Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Simplify and standardise Java EE Security - origin of JSR 375 #10
In Java EE declaring security constraints via e.g. @RolesAllowed, programmatically checking them via e.g. HttpServletRequest#isUserInRole and triggering a container login via HttpServletRequest#login is all relatively straightforward.
Unfortunately, providing the logic for the actual authentication and role mapping/retrieval remains a cumbersome exercise. This is especially painful for simple applications which don't need elaborate security abstractions. JASPIC (JSR 196) did provide a means to make authentication modules portable in Java EE 6, but actually using those remains a fairly tedious and vendor specific process.
For instance, JBoss AS 7 requires the following steps:
GlassFish requires the user to take different, but similar steps including interacting with a graphical UI (see http://www-02.imixs.com/roller/ralphsjavablog/entry/openid_serverauthmodule_jsr_196_with)
Not only are these steps anti ease-of-use, they are also notoriously non-portable despite JASPIC's promise of portability. Furthermore, having the authentication logic outside the application itself prohibits the developer to easily make use of application domain models and code for the authentication process (which is typical for applications that manage their users internally and don't need to integrate with an overall user directory system of e.g. an enterprise).
I therefor would like to propose standardizing how JASPIC authentication modules can be embedded in (simple) applications in a portable way, and additionally address the use case that for small/test applications even a JASPIC module is too much and something even simpler is needed. This is especially true when the application already makes use of a custom mechanism (typically a Servlet Filter) in combination with HttpServletRequest#login.
Example of simplified authentication/role mapping:
Following the presence of such simplified identity store in the application, the following should hold:
Example of standardized installation of a JASPIC authentication module in application.xml or web.xml:
Alternatively, the presence of a JASPIC authentication module inside the application annotated with a special annotation (perhaps the same one as used for the simplified login module), can have the same effect of having the module automatically installed.
Like the standardized identity store, when such a JASPIC authentication module is declared in an application, no further configuration, role mapping or role declarations should be required, other than those that are specific for the authentication module itself.
I am still considering your proposal above, and I intend to comment further. Generally speaking I think that most of the pieces are in place to support the authentication aspects of your use case; but that we should consider how we might provide applications with interfaces to create application users and/or to assign them privileges (i.e., to roles). As part of our work on the Java Identity API interfaces we would like to make such interfaces available to java apps (although at the current time, our focus is mostly on lookup style interactions).
I also added a comment on the thread in the JBOSS forum see:
regarding support for "remember me", we might consider adding a control flag to HttpServletRequest.login. However it would likely be sufficient to collect this control information as part of the authentication dialog with the user, and apply it in the underlying authentication mechanism. Moreover to facilitate that for FBL, we might consider defining a corresponding optional parameter to accompany j_username and j_password. Where we are using a jsr 196 sam for container authentication, the extraction of the indicated remember me effect from the HttpServletRequest messages could be handled by the pluggable auth module.
There I tried to programmatically register an example SAM on 4 different servers in a portable way. One of the major problems I run into is with the appContext. The spec certainly provides a definition for this for the Servlet Profile, but it's still not clear what an application doing registration should provide here. Different application server implementations also seem to want different things here. Most want "server [application context path]", but JBoss AS/EAP wants ["ServletRequest#getLocalName" [application context path]" here.
The other major problem is that every application server still insists on the user providing a proprietary deployment descriptor, mostly for things like role mapping and the specification of a domain/realm.
Above I asked that the roles returned by the proposed @AppLoginModule would be accepted without requiring to be mapped, but maybe we can go a step further and demand that the roles a JASPIC SAM puts into the JAAS Subject are useable without any required vendor specific mapping?
I think the ideal is that without any vendor specific deployment descriptor present (like WEB-INF/sun-web.xml), roles would be directly accepted. Then if there is such a deployment descriptor present, it can be used to optionally map some or all of the roles. Of course, it's at the vendor's discretion if further options are provided to e.g. completely turn off mapping or to mandate mapping for all roles, etc. This is fine, as long as those options are never the default for any application server.
The ultimate goal is to have basic security working without the need of any kind of vendor specific configuration, deployment descriptors, or whatever. Currently users having such requirements often just completely ignore Java EE security and implement their own solution based on ServletFilters and objects in the HTTP session. When the app grows to a point that it does need the more advanced things that Java EE security offers, it's a pain to replace the homegrown system.
That's why I think Java EE security (as a broad term), should also support the most simple and basic use case.
Slightly abbreviated this will allow an application to define a class like the following that handles both the initial name/password authentication and the "remember me":
In broad lines it follows the approach outlined by Ron above, but instead of j_username, j_password and a new optional parameter, it works with a programmatic HttpServletRequest#authenticate call that passes there parameters via request attributes. This approach works better for a JSF environment, but for JSP/HTML & Servlet apps an additional parameter next to j_username, j_password for the standard FORM based authentication would surely be needed as well.
The SAM I prototyped assumes the user has a service available to retrieve the credentials from by name/password (as in the original proposal), as well as (optionally) a service that can do the same thing for "tokens" that are used for the "remember me".
As of the major problems mentioned above, the appContext issue has been solved by Ron in JASPIC MR2 via JASPIC_SPEC-1.
I've created JAVAEE_SPEC-20 to address the most problematic aspect of the required proprietary deployment descriptor.
A very practical problem I encountered when prototyping the above solution is that CDI and the JNDI component namespaces (java:comp etc) are not setup when a JSR 196 SAM is called before a resource invocation. For this I've created JASPIC_SPEC-14.
For EE 8, we are adding a new JSR focusing on making the Security API simpler and more portable.
We are trying to determined whether we should standardize something like the simple authenticator UsernamePasswordAuthenticator you suggested. A question that came up was: Would a "typical" app developer using "simple" authentication really want to implement the authenticate method? It seems username/password or token authentication would be a service that an app developer would want the server to handle. How would an application domain model change the typical username/password verification?
Is the real driver behind a simple authenticator API the ability to have an app manage its own users, groups, and roles dynamically? What if we added portable APIs for user, group, and role management? Would that eliminate the "typical" need for an app developer to implement an authenticator?
That said, there are obviously special authentication mechanisms beyond username/password that an application may want portable access to. Perhaps improvements to JASPIC to fix the portability problems would be the way to address the broader authentication API.
But, for the "simple" case, would adding the following APIs address the need for a simple authenticator?
1. Standardized User Service API, with:
No surprises here, as this is reflecting suggestions made in this and other JIRAs. But does the ability to manage users, groups, roles achieve the goal desired by implementing "KickoffAuthenticator"? It seems the value of this authenticator is in the KickoffAuthenticator.getApplicationRoles(). It seems KickoffAuthenticator.authenticate() would be boiler-plate code.
A concern with requiring applications to implement UsernamePasswordAuthenticator.authenticate() is it provides an opportunity for insecure code and vulnerabilities.
Please respond with your thoughts.
I think the answer to this would be "yes" when looking at how often I've seen developers do this. Because Java EE doesn't offer anything to help them with this, I'd mostly see them avoiding Java EE security completely and just implementing something using Servlet Filters.
The problem with this is that those usernames and passwords for simple applications are not in the server, and that the way the server handles this is different for each and every server. This makes it incredibly hard to explain how one should do this task in "Java EE". Instead, one has to explain that one part is done using Java EE code, and the other part is done using JBoss code. But then the user happens to be using Hitachi Cosminexus, and who knows how proprietary login modules are configured for Hitachi Cosminexus?
There's a similar problem with doing cloud deployments, where often everything has to come from the war (or ear) and there's no option to configure anything at the side of the server.
An application often has a number of domain entities. E.g. for an online advertising application there could be an Advertisement which is owned by an Advertiser. Such an Advertisement can be put on a Website owned by a Publisher.
In such application, Advertiser is a user who can register with the system and then login. Same goes for Publisher.
It's thus an impediment if authenticating can only be done via users that are somehow magically present inside some store managed by the application server, since those users are primarily entities that exist within the application. They register with the application via a webpage that's integrated with the main application.
Application server vendors have long recognized this particular use case, since many of them come with "DatabaseLoginModules". This often boils down to pointing such login module with vendor specific configuration to the same database that happens to store the above mentioned users, and then fabricate a (SQL) query via which a username and (hashed) password can be extracted from the table(s) that store those users.
This often means that the data source has to be defined twice, and there has to be separate logic, often even separate from the application code, that has to have internal knowledge of how the user is mapped to the database tables. If the application changes the user layout, this query will break.
Absolutely, hence the idea to have a couple of interfaces for a small and finite number of well known use cases. If the application's need can not be met by using once of those, then there's always full blown JASPIC which by virtue of its immensely generic API could theoretically do "anything".
For sure, and maybe even up to the point that having the simplified authenticator might be less needed.
Basically, having a SAM registrable via a simple annotation instead of having to go through 4 factories, having CDI and Java EE component namespaces available in it, and providing a convenience base class and methods (see JASPIC_SPEC-17 , HttpMsgContext and HttpServerAuthModule) could come a long way.
If you mean low level CRUD operations, then I'm not so sure about this. There's JPA and EJB for that after all. If you're talking about a specific API for CRUD operations on whatever "user repository" that is used by a SAM or LoginModule, then this may be an interesting feature to look at. However, I think not all repositories are able to support CRUD operations easily. In-memory, .properties, database and LDAP probably can, but OAuth (Facebook, Twitter etc) probably can't.
I'm afraid it also still wouldn't solve the case where the user that's logging in is primarily an application entity. If I understand what you mean with "CRUD operations" correctly, then an application would always have to call two APIs. E.g. when creating a user it would have to call both JPA and this new API, just so the authentication system also knows about the new user. In such case transactions are critical, but this will probably make the entire thing way more complicated, both for implementors of the spec as for users of the spec.
What would the interface of such User Service look like? Wouldn't this basically be the same as the interface proposed here and in JAVAEE_SPEC-25? E.g. a service where you call a method and pass in a username and password, and get back a "user" represented by a name and set of roles. Essentially it's a simpler and more modern version of the JAAS LoginModule.
This is like the CRUD operations on Users, right? There may be some merit here for some applications and some "repositories", but I don't think this will solve the general case. I think the general case is that the application has already stored users and role associations in some format using whatever existing API (JDBC, JPA, etc). In that case it doesn't need a new API to store anything, but just a way to return a name + roles to Java EE.
What I think you are proposing (correct me if I'm wrong) is another persistence API (next to JDBC and JPA among others) specifically tailored for storing Users, Groups and associations between these two. While it could indeed be handy to have a universal API for these things for say LDAP when there's an LDAP login module configured, or to an XML file when there's some XML file based login module configured, I think it's solving a different (and rather complex) problem.
But isn't that the same opportunity that's there now when applications implement a full blown JASPIC SAM? And simple applications will now most of the times implement something much worse in a Servlet Filter.
The idea is that simple applications could start with implementing something like UsernamePasswordAuthenticator.authenticate(), and could then later on fairly transparently swap it out for a more secure implementation (of which the Java EE standard could provide a number of default ones like proposed by JAVAEE_SPEC-28).
All in all I think it might be a good idea to get all the separate ideas together once this new security JSR has really started in a kind of big picture issue, e.g.
Thanks for your prompt response.
Let me explain the UserService and RoleService a bit.
UserService is an application-scoped service for an application to manage its own users. User data would be supplied by a UserSource, which may point to an application-supplied persistence store or the server user store. This user collection may be completely independent from the server users, or may be the same, depending on configuration. The components may look something like this:
Standardized UserSource types:
The UserSource would be defined as a resource. The UserService would be a persistence API for storing Users, Groups, and associations, however the underlying repository may be application supplied. The users supplied by the UserService would be local to the application, however multiple applications could access the same user repository to share users.
We could have a read-only and read-write version of UserService, or otherwise determine the capability of a UserService. That is, some repositories are read-only. Also, we may split out the Password into a separate service/repository.
The UserSourceDefinition annotation would be the default, overridable via standard deployment descriptor, and programmatically via standard APIs.
RoleService would have a similar architecture as the UserService. RoleService would also be a resource, and defines role mappings local to an application, but may be configured to use the server role mapper. The components may look something like this:
Standardized RoleMapper types:
The RoleMapperDefinition annotation would be the default, overridable via standard deployment descriptor, and programmatically via standard APIs.
Finally, the application server discovers which UserSource and RoleMapper to use for an application by processing the Authenticator annotation:
The Authenticator annotation would apply to the application scope, be overridable via standard deployment descriptor, and be overridable programmatically via standard APIs.
The UserService and RoleService attempt to provide simple and portable user and role management to applications.
Applications would be able to bind their own user repositories into a server's authentication process for that application. The "simple" authenticator API could just be the @Authenticator annotation. More advanced/custom authentication mechanisms could use JASPIC, which as you mentioned, needs some work.
The UserService, Role Service, and binding Authenticator could be a way to do that.
Please respond with your thoughts.
I do think it's especially important to establish some terminology and to take a look at how all individual ideas come together as a whole.
Specifically there are two concepts that often come up and actually exist, but haven't got real clear distinguishing names:
The first item is what's more or less called "auth-method" in the Servlet spec, and "auth module" in the JASPIC spec. The second item is very indirectly called "realm" in the Servlet spec, but you'll often see the terms "repository" and "store" as well. JASPIC (optionally) delegates this functionality to a JAAS "LoginModule". JAVAEE_SPEC-28 calls these "security providers".
The reason I'm bringing this up here is that if I understood correctly this second item corresponds to what you call a "UserSource" and a "UserService" (and in the running text refer to using "repository")
A second issue, directly related to the above is that I'm wondering what the difference is between a UserSource and a UserService. In the example code they seem to be the same thing. There, a variable of type UserService is injected with a UserSource:
One thing I'm missing in the examples and API is a way to retrieve the groups/roles. This information is not in your UserInfo and the LdapUserSourceDefinition doesn't show any attribute used to hold the groups/roles query.
In practice, there are often two queries defined for repositories. Eg for both SQL/DB and LDAP repositories you define one query to obtain just the user and another one to obtain the roles associated with a user. Some repositories, like a file based one, have their own internal format to store both users and their roles and no separate queries are needed. Yet other repositories, such as the increasingly popular OAuth based ones (Facebook, Twitter, ...) don't return roles at all (the app typically stores roles locally instead).
As for the RoleMapper examples, here too I wonder what the difference is between the RoleMapper and RoleService; they seem to be the same thing as a RoleService variable is injected with a RoleMapper.
I also wonder if LDAP can actually be used for (local) role mapping. It's sure used for role retrieval, but is it really used for local application role mapping? I don't think I've ever seen that.
Finally, we may consider if the terms "group" and "role" are really needed. As you of course know, there's a third level of role mapping possible between the global application level roles and the roles of a single Java EE component (EJB bean or web module). There both source and target keeps using the term "role". I recognise that "group to role mapping" is an existing and reasonably well known term, but going forward with simplifying security it might be worth it to reconsider if those two terms are really needed.
The problem I'm seeing is that in practice people dream up all kinds of fancy semantics related to the terms "group" and "role", thinking group is really like a group in normal English, while a role is more akin to a right, and what have you. Never ever have I seen anyone who intuitively understood that "group" is the "thing" returned by the auth module/login module and "role" is the "thing" after the mapping as required by some servers.
With standardised role mapping one thing in favour of keeping the group / role terms though is that people could now start using it as the names intuitively imply; coarse grained / fine grained permissions.
As for the authenticator example as given below:
I think there are a few things to remark here.
Given the above mentioned distinction between the auth "method" and the "repository", I think the first one should be put here too. The method is after all not an alternative to the repository but a higher layer in a way; the method may decide not to call into a repository, but a repository always needs to be called by a method.
A small cosmetic thing is that in JNDI it's a kind of de facto standard that "name" is an overloaded mess that both sets a name when a resource is defined and injects a name into the ENC (if any) when referenced. For referencing an existing name "lookup" seems to be more common.
Another thing is that while for the example OneToOneRoleMapper is great, in practice I think this could better be the default for this kind of ease of use facility.
Finally, I wonder if the API for this annotation would not be better off using CDI names and/or qualifyers instead of or in addition to JNDI.
Anyway, keeping JNDI and the default role mapper it would then be something like this:
In this example java:app/prodAuthMethod would refer to a configuration of a JASPIC module or one of the standard auth methods (like FORM). Bonus points for if there would not be a difference between those two and FORM was just a standardised JASPIC module.
We now have the method which uses eg a form to get a username and password from the actual user, we have a userSource that retrieves the user (and presumably the roles) and we tell the server to use the roles directly.
There's now just one thing missing (apart from the role retrieval mentioned above); what code is responsible for comparing the submitted password against the actual password? This has to be custom code too, as in general the server cannot assume any specific format or hash method/salt etc of the password (or any other type of credential).
The UserSource would be an adapter between the repository and the UserService. We would standardize UserSource implementations for various repository types (LDAP, DataSource, etc). The UserService would provide user operations, delegating repository access to the UserSource. I suppose we could simplify and merge UserSource and UserService, perhaps standardize some service helper methods.
Sorry, missed that in the reply. Groups are just groups of users, with no authorization semantics without RoleService. To get groups from UserService:
Roles provide authority. To get role from RoleService:
Note that the GroupIsRoleMapper would represent groups as roles.
I would expect the standardized LDAPUserSource, DataSourceUserSource, etc, would be configurable for apps to declare queries for specific required operations.
UserService would be meant for applications to manage users. For OpenID Connect user repositories, I would expect a JASPIC SAM to cover that.
Yup, perhaps we should simplify this terminology and just have RoleService implementations.
I was not sure if that was actually used, although I think it is possible. No need to standardize an uncommon use case.
One idea we were considering was having role mapping be rule based. We could have the role mapping rules be based on EL, incorporating managed beans. We could store the rules inline or externally in file or LDAP. The rules would be evaluated before authorization decisions.
Group to role mapping arguably is needed for deployments where the enterprise is using applications developed by a third party. The mapping allows application authorization roles to be assigned from enterprise users. The one to one role mapper would provide a simplification for applications not requiring the mapping. I am not sure how to get away from role mapping and still accommodate the common Java EE security use cases.
I think using JNDI is the current standard for referring to resources. Although CDI seems like the "hammer for everyone's nail", I could not find any standards for using CDI names to refer to resources.
I agree with this. authMethodLookup would make sense if JASPIC were updated to be configurable with standardized SAMs. The absence of authMethodLookup infers the currently determined authmethod (e.g., via web.xml) would use the specified UserSource and RoleMapper for authentication within the application.
Since the UserService internally hashes/encrypts the password, I think the UserService should encapsulate that decision. For example, we could remove the Password attribute from UserInfo and add a UserService operation which would encapsulate the password check, like:
That said, we are also considering separating Password into a separate service: PasswordService or CredentialService. This would facilitate having a separate, more secure credential repository.
Hmmm, hopefully it will be possible to come to an abstraction where there will be no need for one group of authentication methods to have a different API/SPI.
Yes, of course. But that wasn't what I meant Group to role mapping is a key requirement for the above use case and definitely shouldn't be done away with. What I meant is that the term group may not be necessary and could just be called role as well.
E.g. we now have:
| Term | Meaning |
The term group specifically is a source of confusion. People dream up all kinds of meanings for it, EXCEPT the meaning "organization wide role". I wasted so many hours trying to explain to different developers and in the end I think they still felt that group meant something else than it actually means.
group is also not entirely consistently used. JASPIC recognizes the term and uses it in its API/SPI but JACC does not.
Role ref is a problematic term too, but in practice not a big issue since it defaults to Role anyway and I think in practice people don't really use it (correct me if I'm wrong).
Although longer, I feel calling the process something like "organization role to application role mapping" or somewhat shorter "organization to application role mapping" is quite a bit clearer. Alternatively, "global" could be used instead of "organization" as well, and "application" could be abbreviated leading to: "global to app role mapping". The new role hierarchy (wrt terminology) could then become:
| Term | Meaning |
CDI beans can be explicitly named (@nAmed annotation in user code, or the getName method in the Bean type for extensions).
Should applications always subclass the UserService then, or do you envision a configurable choice of some well known standard hash/encrypt methods and a subclass or plug-in type if the algorithm the user uses is not among the standard choices?
Thus could you also consider to implement the API which support the SSHA ?
Originating from 2012(!) this is the true quintessential issue that eventually led to the creation of JSR 375. Many interesting things are discussed in the comments, some of which we have done almost exactly as proposed there, and some of which we approached totally differently.
Closing as there's nothing concrete to be done for this anymore.