users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Working example app demonstrating identity store usage

From: Werner Keil <werner.keil_at_gmail.com>
Date: Mon, 7 Dec 2015 10:45:24 +0100

Thanks, I hope to have a closer look at it during the week or weekend.
Would be nice to show something like it in Tel Aviv in 10 days ;-)

Kind Regards,

Werner Keil | JCP Executive Committee Member, JSR 363 Co Spec Lead |
Eclipse UOMo Lead, Babel Language Champion | Apache Committer

Twitter @wernerkeil | @UnitAPI | @JSR354 | @AgoravaProj | @DeviceMap
| #DevOps | #EclipseUOMo
Skype werner.keil | Google+ gplus.to/wernerkeil



Werner Keil
[image: https://]about.me/wernerkeil
<https://about.me/wernerkeil?promo=email_sig>


On Mon, Dec 7, 2015 at 10:37 AM, arjan tijms <arjan.tijms_at_gmail.com> wrote:

> Hi,
>
> I have extended the example a little. To keep the original example as-is
> and as small/simple as possible, I did the extended work in a new repo
> here: https://github.com/arjantijms/mechanism-to-store-x
>
> This adds:
>
> * Working implementation and example of @DataBaseIdentityStoreDefinition
> * Example of custom (app provided) identity store.
>
> See:
>
> *
> https://github.com/arjantijms/mechanism-to-store-x/blob/master/app-db/src/main/java/test/Servlet.java
> *
> https://github.com/arjantijms/mechanism-to-store-x/blob/master/app-custom/src/main/java/test/TestIdentityStore.java
>
> I also fixed the "mechanism-to-store-app-1.0-SNAPSHOT" name. The example
> now uses simple names for the war and therefor the URL:
> localhost:8080/app-db, localhost:8080/app-mem, localhost:8080/app-custom.
>
> The examples were tested on GlassFish (4.1.1) and JBoss (WildFly 10rc4).
> Note that JBoss needs the proprietary JASPIC activation before this works
> (still hoping Darran can do something here to lift this).
>
> In order to work around a GlassFish bug (see
> https://java.net/jira/browse/GLASSFISH-21447) I had to put the data
> source in java:global. Due to another GlassFish bug where GF doesn't unbind
> the data source when the application is undeployed you actually have to
> stop and start GlassFish before the deploying the app again.
>
> Kind regards,
> Arjan Tijms
>
>
>
>
> On Sun, Oct 25, 2015 at 5:55 AM, Alex Kosowski <alex.kosowski_at_oracle.com>
> wrote:
>
>> Hi Arjan,
>>
>> That example app is terrific! I would like to demonstrate it during the
>> JavaOne JSR 375 BOF. The app does not look like much, but when you realize
>> the caller was authenticated using data from an annotation, you realize how
>> these simple standardizations will make a BIG impact.
>>
>> The only issue I ran into when deploying on GlassFish 4.1 was the default
>> app name was " mechanism-to-store-app-1.0-SNAPSHOT", which made the context
>> root " /mechanism-to-store-app-1.0-SNAPSHOT". But I changed the context
>> root to "/mechanism-to-store-app" in the GF admin console and the example
>> works as you described.
>>
>> Thanks again!
>> Alex
>>
>>
>> On 10/24/15 6:19 PM, Alex Kosowski wrote:
>>
>> Thanks Arjan,
>>
>> Perhaps you would provide an example of using the
>> @CredentialCapable(UsernamePasswordCredential.class) qualifier? Also,
>> perhaps you would have an example of extending a standard identity store
>> with a custom defined one to support a custom defined credential?
>>
>> Just some suggestions.
>>
>> With regards,
>> Alex
>>
>> On 10/19/15 2:53 PM, arjan tijms wrote:
>>
>> Hi,
>>
>> On Mon, Oct 19, 2015 at 7:46 PM, Alex Kosowski <alex.kosowski_at_oracle.com>
>> wrote:
>>
>>> Thanks Arjan! I cannot wait to try it!
>>
>>
>> Looking forward to hearing feedback, thanks.
>>
>> I'll try later this week to create another project that implements some
>> more identity stores and also has an example for a user defined one.
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>
>>
>>>
>>>
>>> On 10/19/15 1:27 PM, arjan tijms wrote:
>>>
>>>> Hi,
>>>>
>>>> I've created a working zero config demo application that shows how an
>>>> authentication mechanism can use an identity store.
>>>>
>>>> It's located here: https://github.com/arjantijms/mechanism-to-store
>>>>
>>>> It uses a selection of the types Alex proposed, with the adjustments as
>>>> discussed. This demo app uses one of the two ways to set an Identity Store;
>>>> "declaratively for a standard provided store" as proposed by Reza in issue
>>>> https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-9 (the other option
>>>> which is not demoed here is a store fully defined by the application).
>>>>
>>>> The store is declared using an annotation corresponding to option 3 in
>>>> the list presented earlier. I put this annotation on a test Servlet (but it
>>>> can be put anywhere):
>>>>
>>>> @EmbeddedIdentityStoreDefinition({
>>>> @Credentials(callerName = "reza", password = "secret1", groups = {
>>>> "foo", "bar" }),
>>>> @Credentials(callerName = "alex", password = "secret2", groups = {
>>>> "foo", "kaz" }),
>>>> @Credentials(callerName = "arjan", password = "secret3", groups = {
>>>> "foo" }) })
>>>> @DeclareRoles({ "foo", "bar", "kaz" })
>>>> @WebServlet("/servlet")
>>>> public class Servlet extends HttpServlet
>>>>
>>>> See:
>>>> https://github.com/arjantijms/mechanism-to-store/blob/master/app/src/main/java/test/Servlet.java
>>>>
>>>>
>>>> This annotation is picked up by a CDI extension and a Bean<T> is
>>>> created for it:
>>>>
>>>> public <T> void processBean(@Observes ProcessBean<T> eventIn,
>>>> BeanManager beanManager) {
>>>>
>>>> ProcessBean<T> event = eventIn; // JDK8 u60 workaround
>>>>
>>>> Optional<EmbeddedIdentityStoreDefinition> result =
>>>> getAnnotation(beanManager, event.getAnnotated(),
>>>> EmbeddedIdentityStoreDefinition.class);
>>>> if (result.isPresent()) {
>>>> identityStoreBean = new CdiProducer<IdentityStore>()
>>>> .scope(ApplicationScoped.class)
>>>> .types(IdentityStore.class)
>>>> .create(e -> new
>>>> EmbeddedIdentityStore(result.get().value()));
>>>>
>>>> }
>>>> }
>>>>
>>>> This Bean<T> is subsequently registered with the container:
>>>>
>>>> public void afterBean(final @Observes AfterBeanDiscovery
>>>> afterBeanDiscovery) {
>>>> if (identityStoreBean != null) {
>>>> afterBeanDiscovery.addBean(identityStoreBean);
>>>> }
>>>> }
>>>>
>>>> See:
>>>> https://github.com/arjantijms/mechanism-to-store/blob/master/jsr375/src/main/java/org/glassfish/jsr375/cdi/CdiExtension.java
>>>>
>>>>
>>>> The Identity Store implementation is vendor specific. It's not in the
>>>> javax.security API package. This way vendors can optimise the
>>>> implementation and/or map it to their existing artefacts.
>>>>
>>>> The sample implementation maps the data in the annotation to a Map:
>>>>
>>>> private Map<String, Credentials> callerToCredentials;
>>>>
>>>> public EmbeddedIdentityStore(Credentials[] credentials) {
>>>> callerToCredentials = stream(credentials).collect(toMap(
>>>> e -> e.callerName(),
>>>> e -> e)
>>>> );
>>>> }
>>>>
>>>> And in the validate() method it simply checks if the credentials for
>>>> the requested caller name are present:
>>>>
>>>> public CredentialValidationResult
>>>> validate(UsernamePasswordCredential usernamePasswordCredential) {
>>>> Credentials credentials =
>>>> callerToCredentials.get(usernamePasswordCredential.getCaller());
>>>>
>>>> if (credentials != null &&
>>>> usernamePasswordCredential.getPassword().compareTo(credentials.password()))
>>>> {
>>>> return new CredentialValidationResult(
>>>> VALID,
>>>> credentials.callerName(),
>>>> asList(credentials.groups())
>>>> );
>>>> }
>>>>
>>>> return INVALID_RESULT;
>>>> }
>>>>
>>>> See:
>>>> https://github.com/arjantijms/mechanism-to-store/blob/master/jsr375/src/main/java/org/glassfish/jsr375/identitystores/EmbeddedIdentityStore.java
>>>>
>>>>
>>>> The application uses a very basic SAM. This one uses the plain
>>>> non-simplified JASPIC API. The SAM obtains the identity store via CDI and
>>>> then utilises it to perform the "credential to identity data" function:
>>>>
>>>> String name = request.getParameter("name");
>>>> Password password = new Password(request.getParameter("password"));
>>>>
>>>> // Obtain a reference to the Identity Store
>>>> IdentityStore identityStore =
>>>> CDI.current().select(IdentityStore.class).get();
>>>>
>>>> // Delegate the {credentials in -> identity data out} function to
>>>> // the Identity Store
>>>> CredentialValidationResult result = identityStore.validate(new
>>>> UsernamePasswordCredential(name, password));
>>>>
>>>> if (result.getStatus() == VALID) {
>>>> callbacks = new Callback[] {
>>>> // The name of the authenticated caller
>>>> new CallerPrincipalCallback(clientSubject,
>>>> result.getCallerName()),
>>>> // the groups of the authenticated caller (for test
>>>> // assume non-null, non-empty)
>>>> new GroupPrincipalCallback(clientSubject,
>>>> result.getCallerGroups().toArray(new String[0])) };
>>>> } else {
>>>> throw new AuthException("Login failed");
>>>> }
>>>>
>>>> See:
>>>> https://github.com/arjantijms/mechanism-to-store/blob/master/app/src/main/java/test/TestServerAuthModule.java
>>>>
>>>>
>>>> Finally the demo app uses a simple (non-protected) Servlet (the one
>>>> shown above) that prints out the details of the authenticated user. If the
>>>> application is deployed to a stock GlassFish without any configuration
>>>> whatsoever being done it can be requested via:
>>>>
>>>>
>>>> http://localhost:8080/mechanism-to-store-app/servlet?name=reza&password=secret1
>>>> <
>>>> http://localhost:8080/mechanism-to-store-app/servlet?name=reza&password=secret1
>>>> >
>>>>
>>>> If all went well this prints out the following:
>>>>
>>>> This is a servlet
>>>> web username: reza
>>>> web user has role "foo": true
>>>> web user has role "bar": true
>>>> web user has role "kaz": false
>>>>
>>>> Needless to say here that this is just for demo'ing one of the smallest
>>>> possible SAMs that interact with the caller. Putting the password in the
>>>> URL is of course not suited for any real live usage.
>>>>
>>>> Note that this particular demo only demonstrates a few of the discussed
>>>> options. I also made a few practical choices here and there to be able to
>>>> implement the application which can of course be discussed further.
>>>>
>>>> Thoughts?
>>>>
>>>> Kind regards,
>>>> Arjan Tijms
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>
>