users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Application-based Group-to-Role Mapping

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Sun, 25 Oct 2015 23:38:06 +0100

Hi,

On Sun, Oct 25, 2015 at 5:19 PM, Alex Kosowski <alex.kosowski_at_oracle.com>
wrote:

> 1. The feature takes the container out of the loop regarding the
> Group-to-Role hierarchy, and delegates that mapping solely to the
> application via JASPIC.
>

Indeed, if the mapping is 1:1, meaning the container doesn't insist on
mapping the groups later on in the chain (via JACC, see all the way below),
then effectively an application supplied JASPIC SAM or an application
supplied JSR 375 IdentityStore can perform any mapping it likes.

Since the container (JACC) doesn't interfere, it doesn't matter if the SAM
or the IdentityStore does any mapping.

As an example, suppose we have a database that lists the groups "foo" and
"bar" for user Peter.

An application specific IdentityStore can read "foo" and "bar", then using
some internal logic map this to say "kai", "bad", "zak" and return that to
the SAM. The SAM then directly passes these "roles" to the container.

But, the application could just as well use a standard IdentityStore that
does not do mapping. This IdentityStore then returns "foo" and "bar" to the
SAM. Now an application specific SAM could instead of directly passing
these roles to the container first map these to "kai", "bad", "zak" and
then pass that to the container.

Here the end result is the same and it doesn't matter which of those two
artefacts does the mapping. For the application developer it likely depends
on which of those artefacts is controlled by the developer.

It could be that neither is controlled by the developer though, say if one
of the standardised IdentityStores is used (say LDAPIdentityStore) and one
of the standard authentication mechanisms (say FORM). In that case an
explicit role mapper may still be useful, but a CDI interceptor may also be
an option.



> 2. The proposed IdentityStore result CredentialValidationResult [...]
> does not need the getCallerRoles method, [...]
>
> 3. JASPIC GroupPrincipalCallback is good enough. [...]
>

Agreed



> 4. To dynamically change a caller role while the application is running
> (e.g., upgrade a user from "Basic" membership to "Premium" membership), the
> application would have to do something like:
>
> 1) The application would have to update the application-managed
> persistence store backing the IdentityStore (e.g., LDAP, DB) to assign the
> updated roles to the caller.
> 2) The caller would have to logout and login to re-authenticate and get
> new roles via the IdentityStore and applied to the container via JASPIC.
>

Technically JASPIC auth modules always (re-) authenticate with every
request, so the role change *could* take effect the next request. In
practice however the authentication result is often stored in the session
and then re-applied from there every request.

What you could do to combine the flexibility of per-request authentication
with the performance of storing the data in the HTTP session, is only
storing in the session that "peter" (caller name) is authenticated, and
then getting the authentication data (including the roles) from a global
cache. The global cache can be invalidated or updated from outside the
session.


5. Embedded role mapping would simply be handled by the
> EmbeddedIdentityStore. Embedded role mapping was originally proposed using
> this annotation:
> @EmbeddedRoleMapper( {
> @RoleMap(user=“foo”,roles=“admin”),
> @RoleMap(group=“admin”,roles={“admin”,”manager”}) } )
> public class MyServlet { }
>
>
> But based on #1 above, the following annotation seems sufficient:
> @EmbeddedIdentityStoreDefinition({
> @Credentials(callerName = "reza", password = "secret1", groups = {
> "foo", "bar" }),
> @Credentials(callerName = "alex", password = "secret2", groups = {
> "foo", "kaz" }),
> @Credentials(callerName = "arjan", password = "secret3", groups = {
> "foo" }) })
>

That would indeed be sufficient in this case. Of course it would hold for
every identity store and not just for EmbeddedIdentityStore.




> Please let me know if you agree with this understanding. Based on the
> above, the application-based role mapping is really just the IdentityStore
> API + One-To-One group-to-role mapping + JASPIC. The existing JASPIC
> callback handlers would be sufficient.
>

True for the most part.

There's only one part though that hasn't been mentioned here, and that's
JACC. It's typically a JACC "authorization module" that needs to call a
role mapper (see
http://arjan-tijms.omnifaces.org/2015/03/java-ee-authorization-jacc-revisited.html
).

I'm not sure if we're still able to handle this case, or whether something
can be done here via a JACC MR.

The idea however is that custom JACC authorization code can obtain a
reference to the existing container provided role mapper and use it via a
standard API. It's a small step from there to also have a portable
definition for the group to role mapping (which is currently done by
proprietary deployment descriptors such as glassfish-web.xml and
weblogic.xml).

Alternatively, as you mentioned above, an application can always set role
mapping (assumed to be eventually done by JACC) to 1:1 and either really
not use any role mapping or map in either the IdentityStore or the
authentication module in a custom way.

Kind regards,
Arjan Tijms