[SERVLET_SPEC-114] Standardize authentication modules in Servlet Created: 31/Oct/14  Updated: 31/Oct/14

Status: Open
Project: servlet-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: arjan tijms Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: authentication, jaspic, jsr-196, security

 Description   

13.6.5 of the Servlet spec says that it's recommended that Servlet containers use the Servlet Container Profile of the Java Authentication SPI for Containers (aka JASPIC, i.e. JSR 196).

In order to facilitate portability and a steady base to build upon for the entire Java EE platform, I'd like to propose to change this from "recommended" to "mandated".



 Comments   
Comment by arjan tijms [ 31/Oct/14 ]

P.s, a change in section 15.3.3 is also needed.

This section now says that all Servlet containers must implement JASPIC in a Java EE product or a product that supports JASPIC.

For this section I'd like to propose removing the conditional so that the section simply holds for all Servlet containers.

The section in 15.3.3 now reads as follows:

In a Java EE product, or a product that includes support for The Java
Authentication SPI for Containers (JASPIC, i.e, JSR 196), all Servlet
containers MUST implement the Servlet Container Profile of the JASPIC
specification.

After the proposed change this would become:

All Servlet containers MUST implement the Servlet Container Profile of the JASPIC
specification.

For completeness, the section in 13.6.5 now reads:

To facilitate portable implementation and integration of additional container authentication
mechanisms, it is recommended that all Servlet containers implement the Servlet Container
Profile of The Java Authentication SPI for Containers

After the proposed change this would become:

To facilitate portable implementation and integration of additional container authentication
mechanisms, it is mandated that all Servlet containers implement the Servlet Container
Profile of The Java Authentication SPI for Containers





[JAVAEE_SECURITY_SPEC-10] Simplify and standardize authentication & role mapping Created: 27/May/12  Updated: 07/Jan/15

Status: Open
Project: javaee-security-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Major
Reporter: arjan tijms Assignee: alex.kosowski
Resolution: Unresolved Votes: 12
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: authentication, authorization, ease-of-use, jaspic, rolesallowed, security

 Description   

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. JASPI/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:

  1. Create a named security domain outside the application in a vendor specific way, that's tied to a specific AS instance.
  2. Connect the JASPI authentication module to this security domain in a vendor specific way.
  3. Declare in web.xml that JASPI is the realm.
  4. Link the (web) application itself to the global security domain using a vendor specific descriptor.
  5. In the vendor specific descriptor, specify an internal vendor specific class name that's internally needed to activate JASPI.

(See https://community.jboss.org/wiki/JBossAS7EnablingJASPIAuthenticationForWebApplications)

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 JASPI'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 JASPI 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 JASPI 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:

@AppLoginModule
public class MyAuthenticator implements PasswordLoginModule {

    private User user;

    @Inject
    private UserService userService;

    public void authenticate(String name, String password) {
        user = userService.getByNameAndPassword(name, password);
        if (user == null) {
            throw new FailedLoginException();
        }
    }

    public String getUserName() {
        return user.getName();
    }

    public List<String> getApplicationRoles() {
        return user.getRoles();
    }
}

Following the presence of such simplified login module in the application, the following should hold:

  • The application is considered to be in a default security realm.
  • The application will make use of this security realm (no explicit mention in web.xml required).
  • Whenever a container login is triggered, MyAuthenticator is used for authentication (only username/password supported of course)
  • If authentication succeeds, the String returned by getUserName will be what HttpServletRequest#getUserPrincipal.getName() and corresponding methods in EJB etc return.
  • For each String inside the list returned by getApplicationRoles, methods like HttpServletRequest#isUserInRole will return true, and annotations like @RolesAllowed referencing those will be considered satisfied.
  • No upfront declaration of roles in any descriptor is required.
  • The roles returned by getApplicationRoles should be directly useable in the application. Specifically, things as (vendor specific) group to role mappings (such as what happens in GlassFish) should not be required.

Example of standardized installation of a JASPI authentication module in application.xml or web.xml:

<server-auth-module>
    <class-name>my.example.HTTPBasicServerAuthModule</class-name>
    <property>
        <name>usersProperties</name>
        <value>somepath/users.properties</value>
     </property>
</server-auth-module>

Alternatively, the presence of a JASPI 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 simplified login module, when such a JASPI 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.



 Comments   
Comment by perissf [ 21/Aug/12 ]

Arjan, I support your feature request, and would like to add my point of view. When developing a "Remember me" feature, the application needs to authenticate the user in the absence of a password. The same application, wants to authenticate with username & password on the first login attempt, and wants to have a container-managed authentication through HttpServletRequest#login. This is clearly not possible in the "Remember me" situation, unless the application stores the password somewhere in clear text. Or unless developing a custom authentication module. Please correct me if I am wrong.

Comment by rmonzillo [ 30/Aug/12 ]

common configuration of SAM's in compatible Servlet containers is something that JASPIC facilitates, but we need to give better guidance on how to accomplish that (by registering a common AuthConfigProvider at the target platform). The Glassfish RI includes the JAASServletAuthConfigProvider as one such AuthConfigProvider. We are creating examples of the portable use the JASPIC methodology under the Nobis Project see:
http://java.net/projects/nobis/sources/git/show/Nobis/authentication

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:
https://community.jboss.org/wiki/JBossAS7EnablingJASPIAuthenticationForWebApplications#comment-10581

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.

Comment by arjan tijms [ 10/Nov/12 ]

Ron, I've created a blog post about this very topic at: http://arjan-tijms.blogspot.com/2012/11/implementing-container-authentication.html

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.

Comment by arjan tijms [ 06/Apr/13 ]

In the meantime I've prototyped a server auth module that approximately does what this issue asks at: http://code.google.com/p/omnisecurity/source/browse/src/org/omnifaces/security/jaspic/OmniServerAuthModule.java

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":

@SessionScoped
public class KickoffAuthenticator implements UsernamePasswordAuthenticator, TokenAuthenticator {

    @EJB
    private UserService userService;

    private User user;

    @Override
    public void authenticate(String name, String password) {
        user = userService.getUserByCredentials(name, password);
    }
    
    @Override
    public void authenticate(String loginToken) {
        user = userService.getUserByLoginToken(loginToken);
    }

    @Override
    public String generateLoginToken() {
        return userService.generateLoginToken(user.getEmail());
    }
    
    @Override
    public void removeLoginToken() {
        userService.removeLoginToken(user.getEmail());
    }    

    @Override
    public String getUserName() {
        return user.getEmail();
    }

    @Override
    public List<String> getApplicationRoles() {
        return user.getRoles();
    }

    @Produces @Named("activeUser")
    public User getUser() {
        return user;
    }
}

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.

Comment by alex.kosowski [ 13/Aug/14 ]

Hi Arjan,

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:

  • CRUD operations on Users
  • CRUD operations on Groups (of Users)
  • Ability to declare (annotation, DD) that a User Service instance is to be used by the server for authentication within the application
    2. Standardized Role (Authority) Service API, with
  • Ability to assign Users or Groups to roles
  • Conditional assignment, of Users or Groups to roles, based on Boolean EL expressions
  • Ability to declare one-to-one Group to Role mapping
  • Ability to declare (annotation, DD) that a Role Service instance is to be used by the server for authorization within the application

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.

Thanks,
Alex

Comment by arjan tijms [ 13/Aug/14 ]

For EE 8, we are adding a new JSR focusing on making the Security API simpler and more portable.

This by itself is really good news

Would a "typical" app developer using "simple" authentication really want to implement the authenticate method?

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.

It seems username/password or token authentication would be a service that an app developer would want the server to handle.

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.

How would an application domain model change the typical username/password verification?

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.

That said, there are obviously special authentication mechanisms beyond username/password that an application may want portable access to.

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".

Perhaps improvements to JASPIC to fix the portability problems would be the way to address the broader authentication API.

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.

  • CRUD operations on Users
  • CRUD operations on Groups (of Users)

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.

Ability to declare (annotation, DD) that a User Service instance is to be used by the server for authentication within the application

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.

Ability to assign Users or Groups to roles

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.

A concern with requiring applications to implement UsernamePasswordAuthenticator.authenticate() is it provides an opportunity for insecure code and vulnerabilities.

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.

  • JASPIC SAM as the clear overall authentication module that takes care of the user interaction/message dialog (among others JAVAEE_SPEC-22)
  • Existing authentication methods implemented as JASPIC SAMs (see also JAVAEE_SPEC-37)
  • Several simplifications / easy of use improvements for SAMs (among others JASPIC_SPEC-17)
  • Simplified interface for just bare authentication that a standard SAM can call in addition to the existing JAAS LoginModule (this issue and JAVAEE_SPEC-25, see also JASPIC bridge profile)
  • Several default implementations of this simplified interface for the most common cases (JAVAEE_SPEC-28)
  • Standardized group to role mapping (JAVAEE_SPEC-20)
Comment by alex.kosowski [ 18/Aug/14 ]

Hi Arjan,

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:

UserInfo <-> UserService <-> UserSource <-> {some user source}

UserInfo properties:
+ Username
+ Password
+ AccountExpired
+ AccountLocked
+ PasswordExpired
+ Enabled
+ Attributes

UserService operations:
+ UserInfo:loadUserByUsername(username)
+ changePassword
+ createUser
+ deleteUser
+ updateUser
+ userExists
+ createGroup
+ addUserToGroup
+ removeUserFromGroup
+ isUserInGroup

Standardized UserSource types:
LdapUserSource: Points to an application supplied LDAP server
ServerUserSource: Bridges to the server users
Jsr351UserSource: Bridges to the JSR 351 Identity API
DataSourceUserSource: Points to an application supplied DataSource
MemoryUserSource: Code-embedded users, or read from file (JSON, XML, or Properties)
CustomUserSource: Application definable

Usage:

@LdapUserSourceDefinition(name=“java:app/prodUserSource”, ldapUrl=“ldap://blah”, ldapUser=“ElDap”, ldapPassword=“#{ALIAS_LDAP}”)

public class MyAuthenticator {	
  @Resource(lookup=“java:app/prodUserSource”)	
  private UserService userService;	
  private boolean isAccountEnabled(String username) {		
    return userService.loadUserByUsername(username).isEnabled();	
  } …
}

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:

RoleService <-> RoleMapper <-> {some role mapper}

RoleService operations:
+ grantRoleToUser(username, role)
+ revokeRoleFromUser(username, role)
+ hasRoleForUser(username, role, includeGroups)
+ getRolesForUser(username, includeGroups)
+ getUsersWithRole(role, includeGroups)
+ grantRoleToGroup(group, role)
+ revokeRoleFromGroup(group, role)
+ hasRoleForGroup(group, role)
+ getRolesForGroup(group)
+ getGroupsWithRole(role)

Standardized RoleMapper types:
LdapRoleMapper: Points to an application supplied LDAP server
ServerRoleMapper: Bridges to the server role mapper
MemoryRoleMapper: Code-embedded role mappings, or read from file (JSON, XML, or Properties)
DataSourceRoleMapper: Points to an application supplied DataSource
CustomRoleMapper: Application definable
GroupIsRoleMapper: Role is one-to-one mapping to user group

Usage:

@MemoryRoleMapperDefinition(
  name=“java:app/devRoleMapper”,	
  users={
    @RoleMap(user=“foo”,roles=“admin”),		
    @RoleMap(group=“admin”,roles={“admin”,”staff”})
  } 
)
public class MyServlet {
  @Resource(lookup=“java:app/devRoleMapper”)
  private RoleService roleService;
  private List<String> getRoles(String username) {
    return roleService.getRolesForUser(username,true);
  }
  …
}

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:

@Authenticator(userSourceName=“java:app/prodUserSource”,roleMapperName=“java:app/OneToOneRoleMapper”)

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.

Regarding:

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.

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.

Regarding:

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.

The UserService, Role Service, and binding Authenticator could be a way to do that.

Please respond with your thoughts.

Thanks,
Alex

Comment by arjan tijms [ 18/Aug/14 ]

Thanks a lot for the thorough explanation. There are a lot of interesting ideas there.

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 (user) interaction method via which credentials are obtained (form, basic, etc)
  • The store where users/callers and optionally the group/role data resides.

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:

@Resource(lookup=“java:app/prodUserSource”)
private UserService userService;

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.

Well, just something to think about

As for the authenticator example as given below:

@Authenticator(userSourceName=“java:app/prodUserSource”,roleMapperName=“java:app/OneToOneRoleMapper” )

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:

@Authenticator(
authMethodLookup="java:app/prodAuthMethod",
userSourceLookup=“java:app/prodUserSource”,
roleMapperLookup=“java:app/OneToOneRoleMapper” )

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).

Comment by alex.kosowski [ 09/Sep/14 ]

I'm wondering what the difference is between a UserSource and a UserService

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.

One thing I'm missing in the examples and API is a way to retrieve the groups/roles.

Sorry, missed that in the reply. Groups are just groups of users, with no authorization semantics without RoleService. To get groups from UserService:
boolean isUserInGroup(String username, String group);
List<String> getUserGroups(String username);

Roles provide authority. To get role from RoleService:
boolean hasRoleForUser(String username, String role, boolean includeGroups);
List<String> getRolesForUser(String username, boolean includeGroups);
List<String> getUsersWithRole(String role, boolean includeGroups);
boolean hasRoleForGroup(String group, String role);
List<String> getRolesForGroup(String group);
List<String> getGroupsWithRole(String role);

Note that the GroupIsRoleMapper would represent groups as roles.

there are often two queries defined for repositories

I would expect the standardized LDAPUserSource, DataSourceUserSource, etc, would be configurable for apps to declare queries for specific required operations.

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).

UserService would be meant for applications to manage users. For OpenID Connect user repositories, I would expect a JASPIC SAM to cover that.

I wonder what the difference is between the RoleMapper and RoleService

Yup, perhaps we should simplify this terminology and just have RoleService implementations.

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.

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.

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.

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.

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.

Agreed

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.

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.

@Authenticator(
authMethodLookup="java:app/prodAuthMethod",
userSourceLookup=“java:app/prodUserSource”,
roleMapperLookup=“java:app/OneToOneRoleMapper” )

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.

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).

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:
boolean isValid( username, password )

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.

Comment by arjan tijms [ 06/Oct/14 ]

UserService would be meant for applications to manage users. For OpenID Connect user repositories, I would expect a JASPIC SAM to cover that.

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.

Group to role mapping arguably is needed for deployments where the enterprise is using applications developed by a third party.

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
Group Organization wide role
Role Application wide role
Role ref Component wide role

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
Global role Organization wide role
Application Role Application wide role
Component Role Component wide role

I could not find any standards for using CDI names to refer to resources.

CDI beans can be explicitly named (@Named annotation in user code, or the getName method in the Bean type for extensions).
More common would however be the usage of bean types (i.e. Java interfaces) and/or qualifiers, which is a type safe approach.

I think the UserService should encapsulate that decision.

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?

Comment by yosshi2008 [ 27/Nov/14 ]

In order to create the application with more strong user authentication,
we would like to insert the password as SSHA(Salted SHA).
And there was no way to implement it as standard.
(It depends on the Application Server.)

Thus could you also consider to implement the API which support the SSHA ?
I assume that It may be influence following API.

UserInfo properties:

+ Password

+ Attributes

UserService operations:

+ UserInfo:loadUserByUsername(username)

+ changePassword

+ createUser

+ updateUser

+ addUserToGroup






[GLASSFISH-18556] Characters out of JASPIC GroupPrincipalCallback Created: 24/Mar/12  Updated: 24/Apr/14

Status: Open
Project: glassfish
Component/s: security
Affects Version/s: None
Fix Version/s: future release

Type: Bug Priority: Critical
Reporter: bjb Assignee: JeffTancill
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: Java Source File PolicyFileTest.java    
Tags: JASPIC, character, exception, group, restriction

 Description   

At this time, not all the characters can be used in a group set by GroupPrincipal callback.

Using thoses character will result into bad PolicyFile with non matching rule.

As a consequence, user will not be granted access as per the JACC checks.

(no exception raised, lowering the log level will result into unrelated exception beeing traced as a wrong track)

Example of such a group is :

ROLE_\01\05\00\00\00\00\00\05\15\00\00\00\8a\16\77\12\f6\70\d2\67\92\01\99\5a\b2\34\00\00

Issues here are the backslash () but I anticipate other characters could be at risks.

AFAIK, at this time there is no restricted character requirement as per JASPIC on the group.



 Comments   
Comment by kumarjayanti [ 25/Mar/12 ]

Will try to get comments from Ron on this.

Comment by bjb [ 26/Mar/12 ]

In the PolicyFile, the parseGrantEntry call

e.codeBase = match("quoted string");

But \ was configure as a quote char !

The internal java.io.StreamTokenizer indicates in line 635, that if a \ is used this is for escaping : C style or octal/hexa. But line 661+ there is no search for a second
to be reaplced by a single \ (aka '
') !

So the problem is whatever we do around \ char we will not get a bijective result (writer/parser).

But I've found reference saying that double backslash was used in PolicyFile as single backslash
http://www.eli.sdsu.edu/courses/spring99/cs696/notes/security/security.html
But I have not found that in the JDK code.

I will see to create a simple testcase for this PolicyFile corner case.
If it confirms my assumptions, I will open a JDK bug.

Until, it is fixes, the \ is a char that should be prohibited from group valid characters until we get the StreamTokenizer fixed

Anyway the domain of values for a name and the bijective nature of PolicyFile has to be confirmed from the JVM team.

Comment by bjb [ 26/Mar/12 ]

I've create a JUnit test case to show the JDK bug :

http://pastebin.com/HxmQJWmk

Comment by monzillo [ 26/Mar/12 ]

http://docs.oracle.com/javase/6/docs/technotes/guides/security/PolicyFiles.html

please see section entitled "Win32 Systems, File Paths, and Property Expansion"

Although I do not think what you are seeing is win32 specific, it seems that you must escape the "\" (when it occurs in your group or role names) with a preceding "\".

Comment by bjb [ 26/Mar/12 ]

JUnit test case to show the issue

Comment by bjb [ 26/Mar/12 ]

I think this has nothing to do with platformspecific as the test I have performed is "in memory" only (see version 2 attached in jira).

First the Policy Writer parser does not use double backslash for the backslash escaping while writing (cf generated policy file from GF).

Then, I can not use multiple escape as the parser (streamtokenizer from James ;P ) did not implement the double backslash escaping as usual in C :
http://en.wikipedia.org/wiki/C_syntax#Backslash_escapes

Most backslashes escapes are handled in the stream tokenizer but the escape of the backslash it self apparently.

I've submit another test case suit with triple (double 1/2) and quadruple (real double) backslash. Only the first test with single backslash (aka octet value) works.





[GLASSFISH-18536] GF callback handler blocking a JASPIC provider when Principal is unknown Created: 21/Mar/12  Updated: 16/Apr/14

Status: Open
Project: glassfish
Component/s: security
Affects Version/s: None
Fix Version/s: future release

Type: Bug Priority: Blocker
Reporter: bjb Assignee: JeffTancill
Resolution: Unresolved Votes: 2
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 2008 64bits


Tags: JASPIC, blocking, groups, principal, unknown, users

 Description   

When sending an unknown Principal (principal not valid as per a local JAAS config) but valid on a global perspective (all checks was done in the JASPIC provider), the GF CallerPrincipal handler will throw a blocking exception in the process :

com.sun.enterprise.security.auth.realm.NoSuchUserException: Cet utilisateur [USER@INTRA-DEV01.DOMAIN-DEV01.LOCAL] n'existe pas. at com.sun.enterprise.security.auth.realm.file.FileRealm.getGroupNames(FileRealm.java:329) at com.sun.enterprise.security.auth.login.LoginContextDriver.jmacLogin(LoginContextDriver.java:566) at com.sun.enterprise.security.jmac.callback.BaseContainerCallbackHandler.processCallerPrincipal(BaseContainerCallbackHandler.java:257) at com.sun.enterprise.security.jmac.callback.BaseContainerCallbackHandler.processCallback(BaseContainerCallbackHandler.java:197) at com.sun.enterprise.security.jmac.callback.ServerContainerCallbackHandler.handleSupportedCallbacks(ServerContainerCallbackHandler.java:76) at com.sun.enterprise.security.jmac.callback.BaseContainerCallbackHandler.handle(BaseContainerCallbackHandler.java:187) at com.sun.enterprise.security.jmac.callback.ContainerCallbackHandler.handle(ContainerCallbackHandler.java:83) at net.java.spnego.PACSpnegoServerAuthModule.updateCallerPrincipal(PACSpnegoServerAuthModule.java:550) at net.java.spnego.PACSpnegoServerAuthModule.validateRequest(PACSpnegoServerAuthModule.java:354) at com.sun.enterprise.security.jmac.config.GFServerConfigProvider$GFServerAuthContext.validateRequest(GFServerConfigProvider.java:1171) at com.sun.web.security.RealmAdapter.validate(RealmAdapter.java:1445) at com.sun.web.security.RealmAdapter.invokeAuthenticateDelegate(RealmAdapter.java:1323) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:551) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:623) at org.apache.catalina.core.StandardPipeline.doChainInvoke(StandardPipeline.java:600) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:96) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Thread.java:662)

The problem is that groups that were provided before with a call to the GF handler (Group handler) is not used but insteand GF access the default realm (file) to fetch the user's groups.

This is blocking usage of non-JAAS bridge profile JASPIC providers.

To lower the state of this issue, either fix the issue or provide a way to bypass this issue.



 Comments   
Comment by bjb [ 24/Mar/12 ]

Hi Kumar,

Please lower the priority level as it is actually not blocking but only misleading.

It will not block non-JAAS bridge but simply push a wrong track to people debugging.

The core issue has been logged as :
http://java.net/jira/browse/GLASSFISH-18556

When runing in JASPIC mode, such an issue should not be raised.

Rgs,
JB

Comment by kumarjayanti [ 25/Mar/12 ]

This issue does sound like it needs a fix. The caller principal callback is trying to do an identity assertion in this case forcing people to also configure a realm that can be used to fetch the groups of the user. This was done to meet requirements of some other usecases but now i realize this is not appropriate. Instead the Group Principal Callback should be explicitly used in this case.

I will fix this for 3.1.2 Patch releases and glassfish trunk.

Thanks for raising this issue.

Comment by arjan tijms [ 13/Apr/13 ]

Is this still the same issue as reported? I've done a lot of JASPIC testing with GlassFish 3.1.2.2 but never encountered this issue. There is something fishy going on though.

The caller principal callback is trying to do an identity assertion in this case

I think you mean the caller principal callback handler right? Since the caller principal callback is a very simple DTO style class that only stores the Subject and the Principal or Name.

The handler (in BaseContainerCallbackHandler.processCallerPrincipal) does a call to the LoginContextDriver, but it itself does not do any identity assertion:

if (isCertRealm) {
    if (principal  instanceof X500Principal) {
        LoginContextDriver.jmacLogin(fs, (X500Principal)principal);
    }
} else {
    if (!principal.equals(SecurityContext.getDefaultCallerPrincipal())) {
        LoginContextDriver.jmacLogin(fs, principal.getName(), realmName);
    }
}

The LoginContextDriver.jmacLogin however does attempt to do this:

 public static Subject jmacLogin(Subject subject, String identityAssertion, String realm) throws LoginException {

        if (subject == null) {
            subject = new Subject();
        }
        final Subject fs = subject;
        String userName = identityAssertion;

        try {
            if (realm == null || "".equals(realm)) {
                realm = Realm.getDefaultRealm();
            }
            Realm realmInst = Realm.getInstance(realm);
            final Enumeration groups = realmInst.getGroupNames(userName);
            if (groups != null && groups.hasMoreElements()) {
                AppservAccessController.doPrivileged(new PrivilegedAction() {

                    public java.lang.Object run() {
                        while (groups.hasMoreElements()) {
                            String grp = (String) groups.nextElement();
                            fs.getPrincipals().add(new Group(grp));
                        }
                        return fs;
                    }
                });
            }
        } catch (Exception ex) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Exception when trying to populate groups for CallerPrincipal " + identityAssertion, ex);
            }
        }
        return subject;
    }

When using JASPIC, the passed in realm will be "" and when that happens this method obtains the default realm ("file") and tries to get the group names from that (realmInst.getGroupNames(userName);).

If this throws an exception (in my testing a NPE is typically thrown) it is ignored by the catch, so the problem as described for this issue doesn't seem to occur anymore (that is, the exception is still thrown, but it doesn't interrupt the authentication flow).

I'm afraid though that if I happened to have this file realm defined with a user that happened to have the same name as the user I'm trying to authenticate with JASPIC, that this user would suddenly get a set of extra roles. If my application happened to have roles with the same name, then this could be a rather big problem.





[GLASSFISH-18528] RuntimeException thown in a JASPIC swallowed and empty page returned Created: 18/Mar/12  Updated: 19/Sep/14  Resolved: 16/May/14

Status: Resolved
Project: glassfish
Component/s: security
Affects Version/s: None
Fix Version/s: 4.1

Type: Bug Priority: Major
Reporter: bjb Assignee: Nithya Ramakrishnan
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows 2008, 64bits


Tags: 4_0_1-approved, debug, empty, jaspic, maze, page, security

 Description   

Any RuntimeException thrown in the JASPIC implementation will result in a empty page in GF (a valid HTML page but with no content and with host encoding as meta) and no log at all (GF security logger set to finest).

IMHO, there should be an isolation so that a RuntimeEx thrown in JASPIC should be intercepted by GF's JASPIC container and :

  • if mandatory : result in a 403
  • if not mandatory : catch & log it appropriately in the security logger and go on with the next implementation configured (as per the spec)

I do not have seen anything about RuntimeEx behavior in the JSR, but this is something that should realy be handled.

FYI, the only solution is to dig with the debugger and it result into a massive loss of time, plus an cloudy situation toward the security : a page was return without clue where it came from.

Rgs,
JB



 Comments   
Comment by Nithya Ramakrishnan [ 16/May/14 ]

A 500 Server error page would now be displayed when a Runtime exception is thrown from the SAM.

Quoting from the JASPIC spec : (Sec 3.8)

"If the request is dispatched to the resource and the resource invocation throws an exception to the
runtime, the runtime must set, within the response, an HTTP status code which satisfies any applicable
requirements defined within the servlet specification. In this case, the runtime should complete the
processing of the request without calling secureResponse"

Sending webintegration/src/main/java/com/sun/web/security/RealmAdapter.java
Transmitting file data .
Committed revision 63277.





Generated at Sun Apr 26 17:17:37 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.