users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Identity Store Proposal 2.0

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Sat, 20 Jun 2015 11:41:31 +0200

Hi,

I took a quick look at Pedro's code, but I'm afraid that this is perhaps
not entirely the right direction (unless it's just a quick mock, of course)

What the code is doing now is essentially how a third party framework would
implement security, largely (or totally) by-passing the existing security
mechanisms of Java EE.

See this code:

@SessionScoped
public class DefaultSecurityContext implements SecurityContext {

    private static final long serialVersionUID = -5054373464615019115L;

    @Inject
    private IdentityStore identityStore;
    private Caller caller;

    @Override
    public Caller getCaller() {
        return this.caller;
    }

    @Override
    public boolean isCallerInRole(String roleName) {
        return this.identityStore.hasRole(roleName, getCaller());
    }

    @Override
    public List<Role> getRoles() {
        if (!isAuthenticated()) {
            return Collections.emptyList();
        }

        return this.identityStore.getRoles(this.caller);
    }

    @Override
    public boolean isAuthenticated() {
        return this.caller != null;
    }

    @Override
    public void login(Credential credential) {
        Support support =
this.identityStore.getCredentialSupport(credential.getClass());

        if (Support.SUPPORTED.equals(support)) {
            Credential validatedCredential =
this.identityStore.verifyCredential(credential);

            if
(Credential.Status.VALID.equals(validatedCredential.getStatus())) {
                this.caller =
this.identityStore.getCaller(credential.getCaller().getName());
            }
        }
    }

    @Override
    public void logout() {
        this.caller = null;
    }

    @Override
    public void runAs(String role, Function<?, ?> function) {
    }
}

Here the identityStore is injected in the SecurityContext which is a
session scoped bean, and directly uses it. So when login() is called, the
result is only known in application space. In particular this means that
security constraints in web.xml, @RolesAllowed in EJB and JACC providers
among others all don't see this.

Also the identity store in the code example is a pretty big thing that does
its own role mapping and own credential selection. I think this is not
really how all the existing identity stores work and that it can be done
with much smaller and orthogonal pieces.

The earlier example that we did in Adam's secspike project had just this as
the identity store, based on interfaces:

public interface IdentityStore extends Serializable {

String getUserName();
List<String> getApplicationRoles();
}

And a credential specific interface this:

public interface UsernamePasswordIdentityStore extends IdentityStore {

boolean authenticate(String username, String password);
}

A concrete implementation is then:

@RequestScoped
public class TestUsernamePasswordIdentityStore implements
UsernamePasswordIdentityStore {

private static final long serialVersionUID = 1L;

@Override
public boolean authenticate(String username, String password) {
return true;
}
 @Override
public String getUserName() {
return "testuser";
}
 @Override
public List<String> getApplicationRoles() {
return asList("USER");
}
}

See
https://github.com/AdamBien/secspike/blob/master/todo/src/main/java/org/secspike/todo/auth/TestUsernamePasswordIdentityStore.java

This is pretty close to what was requested by Reza in
https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-18

Of course the exact details can be tuned. Instead of interfaces, we can
have qualifiers (annotations) and instead of a method per credential type
we can have the single Credential method. E.g.


@RequestScoped
@UsernamePasswordCredential
public class TestUsernamePasswordIdentityStore implements IdentityStore {

private static final long serialVersionUID = 1L;

@Override
public boolean authenticate(Credential credential) {
return true;
}
 @Override
public String getUserName() {
return "testuser";
}
 @Override
public List<String> getApplicationRoles() {
return asList("USER");
}
}

The main difference here is thus that the identity store as shown above is
just a small and highly orthogonal piece of the security architecture that
leverages existing APIs as much as possible, while in the proposal it's a
much bigger thing that embodies a larger part of the security architecture
internally and does more with its own APIs.

Kind regards,
Arjan Tijms













On Fri, Jun 19, 2015 at 5:30 PM, Pedro Igor Silva <psilva_at_redhat.com> wrote:

> Hi,
>
> I've updated the project[1] I was using for JAVAEE_SECURITY_SPEC-12
> with my view of the Identity Store API.
>
> I think it is pretty much aligned with what Alex did but with some
> minor changes. This project also provides two test cases to demonstrate how
> to use both `IdentityStore` and `SecurityContext` together to authenticate
> users when using CDI or just the Servlet API.
>
> @Arjan, I think with this approach is pretty easy to provide an
> "Identity Store Selector" based on a specific credential type given that
> the `IdentityStore` also provides a `getCredentialSupport` method that you
> can use to check if it supports or not a credential type.
>
> I've also considered a `getPermissions` method on the `IdentityStore`
> interface. That would be very useful for Permission Mapping, providing a
> very easy and clean way to obtain permissions (and even check them) from an
> Identity Store.
>
> @Alex, as I told you, I think PL IDM API was very good for an initial
> version. However, I think there is room for simplifications and that is
> what I tried to achieve in this project.
>
> Any feedback is welcome.
>
> [1]
> https://github.com/pedroigor/javaee-security-proposals/tree/identity-store-example/security-context-authentication
>
> Thanks.
> Pedro Igor
>
> [1]
> https://github.com/pedroigor/javaee-security-proposals/tree/identity-store-example/security-context-authentication
>
> ----- Original Message -----
> From: "arjan tijms" <arjan.tijms_at_gmail.com>
> To: "Alex Kosowski" <alex.kosowski_at_oracle.com>
> Cc: jsr375-experts_at_javaee-security-spec.java.net
> Sent: Friday, June 19, 2015 11:04:59 AM
> Subject: [jsr375-experts] Re: Identity Store Proposal 2.0
>
> Hi,
>
> On Fri, Jun 19, 2015 at 2:42 PM, Alex Kosowski <alex.kosowski_at_oracle.com>
> wrote:
>
> > Hi Arjan,
> >
> > Thank you for being so active with this JSR!
> >
>
> No problem ;)
>
>
>
> > Is a credential handler really needed if CDI can already do the
> selection?
> >
> > Here a generic IdententityStore is injected, which in CDI terms
> > may look a bit unusual. Using a CDI qualifier you could inject the
> correct
> > type right away.
> >
> > Eg
> >
> > @Inject @UsernamePassword
> > IdentityStore identityStore
> >
> > Or if it's needed to choose at runtime:
> >
> > CDI.current().select(IdentityStore.class, UsernamePassword);
> >
> > [Alex] What if we did not know the type of credential ahead of time?
> >
>
> That's where the second form of CDI comes in, the CDI.current().select(...)
> (or alternatively, the bean manager based API).
>
> As soon as you can do:
>
> Credentials creds = new UsernamePasswordCredentials("john", new
> Password("welcome1"));
>
> you have the credentials type, namely "UsernamePasswordCredentials". You
> can then ask CDI at runtime (at that moment): "Give me an IdentityStore
> that can handle UsernamePasswordCredentials". JSF now leans very heavily at
> this as mentioned before instead of using it's own handlers and
> registration factories.
>
>
>
> > The registry approach enables multiple CredentialHandlers to be
> > preconfigured to accept varied Credential types. The Credential type
> itself
> > would be used to select the CredentialHandler.
> >
>
> That strongly sounds what CDI already provides. For this EG it would be
> much simpler to go with that (if indeed possible, which it sounds like it
> is), instead of having to design and implement our own APIs.
>
>
>
> > [Alex] How would we use CDI to configure different CredentialHandlers or
> > Backend Stores for different deployments?
> >
>
>
> That's a core value of CDI actually. In fact, much of the reason to use CDI
> in the first place is to have the ability to change dependencies based on
> deployment type. The classical example is for unit testing, but it holds
> for deployment stages as well. The key technology here is the @Alternative
> qualifier and stereotypes. Via beans.xml different alternatives can be
> activated for different deployments. There are quite a number of articles
> about this, but here's one from Antonio:
>
> http://antoniogoncalves.org/2014/05/25/switch-datasource-with-cdi-alternatives-and-stereotypes
>
> In addition to swapping out implementations for different deployments, the
> same mechanism can also be used to let the user provide an alternative
> implementation to a default one that's provided by the container or a
> library. I've written a small article that explains that usage here:
> http://jdevelopment.nl/providing-alternatives-jsf-23s-injected-artifacts
>
>
>
> > [Alex] I know, I just picked a term. I will change the proposal based on
> > the outcome of issue 2
> >
> >
> Okay, great ;) Hopefully it will remain caller, but let's see how the EG
> votes.
>
>
>
> > [Alex] That is what I was thinking. Would we need to request support from
> > JASPIC for a RoleCallbackHandler for containers which distinguish groups
> > and roles?
> >
> >
> I think probably not, at least not if we're standardizing how groups and
> roles currently work. The group to role mapper should be enough here. The
> identity store returns a collection of "names". Those names could be seen
> as either groups or roles. If they are logically seen as roles, then the
> application can configure a 1:1 group to role mapping. E.g. "admin" will be
> mapped to "admin", which "effectively" makes the GroupPrincipalCallback a
> RolePrincipalCallback.
>
> If however we want to introduce new APIs so we can say "isCallerInGroup"
> and "isCallerInRole" down the line, then such new RolePrincipalCallback
> *may* be needed (this will require more thinking though, especially to see
> how this will interact with group to role mapping).
>
> Kind regards,
> Arjan
>