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 17:16:49 +0100

Yep, and at the moment most "authorization" elements are under the somewhat
cryptical
javax.security.jacc

"Java Authorization Contract for Containers API"

Werner

On Mon, Dec 7, 2015 at 5:03 PM, arjan tijms <arjan.tijms_at_gmail.com> wrote:

> Hi,
>
> On Mon, Dec 7, 2015 at 4:42 PM, Werner Keil <werner.keil_at_gmail.com> wrote:
>
>> P.s.: I'm not sure, if the API would stick to a rather lengthy package
>> name like: javax.security.authenticationmechanism ?;-)
>>
>> Werner
>>
>
> I hear you, this package name and specifically the classes inside it, have
> not been given much thought yet, but since they were needed to get the
> sample to work I had to put them somewhere.
>
> In general when we are going to discuss this, there are some issues.
>
> There is already an existing package javax.security.auth.message, which is
> owned by JASPIC, so we won't touch it. But I was wondering about
> just javax.security.auth, which is the prefix package. I guess we could
> touch that (create new sub-packages of that), but this is a bit of an issue
> too since we more or less agreed here that just "auth" is not desirable. It
> can mean either "authentication" or "authorization".
>
> But if we create a package javax.security.authentication next to the
> existing javax.security.auth, where both mean "authentication", it kinda
> looks messy as well.
>
> Nevertheless, with a javax.security.authentication, we could put the
> mechanism classes in javax.security.authentication.mechanism (but in total
> this is actually 1 char longer). The alternative could be
> javax.security.auth.mechanism, but yeah, troublesome...
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
>
>
>>
>> On Mon, Dec 7, 2015 at 10:45 AM, Werner Keil <werner.keil_at_gmail.com>
>> wrote:
>>
>>> 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
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>>
>>>
>>
>