jsr375-experts@javaee-security-spec.java.net

[jsr375-experts] Re: Working example app demonstrating identity store usage

From: Werner Keil <werner.keil_at_gmail.com>
Date: Thu, 24 Dec 2015 12:05:22 +0100

Great, thanks.
Where they do, as a first step the "embedded" API module might still go
into examples (or "proposals" sandbox, which one you think was best) but
soon it would be great to have the Spec/API repo filled with life, too.

I dedicated at least a chapter on security to JSR 375 in my upcoming Social
Java book, too. I should have a bit of time after Christmas to continue
writing ;-)

Kind Regards,
Werner
Am 24.12.2015 11:28 schrieb "arjan tijms" <arjan.tijms_at_gmail.com>:

> Hi,
>
> Yet another update; I extracted interfaces for the classes involved with
> the authentication mechanism proposal. That way we can have a proper
> API/implementation split. I think the example apps are reasonable ready now
> to be moved to the javaee-security-spec repo.
>
> I also added the simplified identity store proposal (a copy from the
> example app) here:
> https://github.com/javaee-security-spec/javaee-security-proposals/tree/master/authentication/identity-store/identity-store-readonly-simplified
>
> I think this properly reflects what had been discussed earlier by Alex, me
> and others, but please check if I did it correctly.
>
> For completeness I'll add the first draft of the authentication mechanism
> as well. This is based on my earlier experiments in OmniSecurity as well as
> various bits and pieces as discussed here. I still think this needs some
> more discussion though, but that can be done in the dedicated thread.
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
> On Wed, Dec 23, 2015 at 3:16 PM, arjan tijms <arjan.tijms_at_gmail.com>
> wrote:
>
>> Hi,
>>
>> Added another update. I added a build-in authentication mechanism (I used
>> a BASIC implementation) and an associated annotation analogous to the ones
>> for build-in identity stores: @BasicAuthenticationMechanismDefinition
>>
>> As mentioned before, it's open question on how to align this with the
>> Servlet EG, but at least there's now an example.
>>
>> With that in place, I created the smallest example application until now.
>> It's basically a single class:
>>
>> @BasicAuthenticationMechanismDefinition(
>> realmName="test realm"
>> )
>>
>> @EmbeddedIdentityStoreDefinition({
>> @Credentials(callerName = "reza", password = "secret1", groups = {
>> "foo", "bar" }),
>> @Credentials(callerName = "alex", password = "secret2", groups = {
>> "foo", "kaz" }),
>> @Credentials(callerName = "arjan", password = "secret3", groups = {
>> "foo" }) }
>> )
>>
>> @WebServlet("/servlet")
>> @DeclareRoles({ "foo", "bar", "kaz" })
>> @ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
>> public class Servlet extends HttpServlet {
>>
>> private static final long serialVersionUID = 1L;
>>
>> @Override
>> public void doGet(HttpServletRequest request, HttpServletResponse
>> response) throws ServletException, IOException {
>>
>> // ...
>> }
>>
>> }
>>
>> As can be seen this chooses and configures both the authentication
>> mechanism as well as the identity store. Both adhere to the highlander rule
>> (there can be only one).
>>
>> The authentication mechanism is implemented as follows:
>>
>> public class BasicAuthenticationMechanism implements
>> HttpAuthenticationMechanism {
>> private final String basicHeaderValue;
>>
>> public BasicAuthenticationMechanism(String realmName) {
>> this.basicHeaderValue = format("Basic realm=\"%s\"", realmName);
>> }
>>
>> @Override
>> public AuthStatus validateRequest(HttpServletRequest request,
>> HttpServletResponse response, HttpMsgContext httpMsgContext) throws
>> AuthException {
>> String[] credentials = getCredentials(request);
>> if (!isEmpty(credentials)) {
>>
>> IdentityStore identityStore =
>> CDI.current().select(IdentityStore.class).get();
>>
>> CredentialValidationResult result = identityStore.validate(
>> new UsernamePasswordCredential(credentials[0], new
>> Password(credentials[1])));
>>
>> if (result.getStatus() == VALID) {
>> return httpMsgContext.notifyContainerAboutLogin(
>> result.getCallerName(), result.getCallerGroups());
>> }
>> }
>> if (httpMsgContext.isProtected()) {
>> response.setHeader("WWW-Authenticate", basicHeaderValue);
>> return httpMsgContext.responseUnAuthorized();
>> }
>> return httpMsgContext.doNothing();
>> }
>> private String[] getCredentials(HttpServletRequest request) {
>> String authorizationHeader = request.getHeader("Authorization");
>> if (!isEmpty(authorizationHeader) &&
>> authorizationHeader.startsWith("Basic ") ) {
>> return new
>> String(parseBase64Binary(authorizationHeader.substring(6))).split(":");
>> }
>> return null;
>> }
>> }
>>
>> Btw, both very good and some less good news concerning JBoss (WildFly).
>> Since WildFly 10rc5 (just released today) ***it's no longer necessary to
>> modify standalone.xml*** :) All JASPIC based examples just run out of the
>> box now. It's not 100% perfect yet, since the archive still needs to
>> contain jboss-web.xml, but that's a minor concern for now.
>>
>> Unfortunately, the basic authentication mechanism doesn't work on WildFly
>> for now, because of this bug:
>> https://issues.jboss.org/browse/UNDERTOW-577
>>
>> The other ones do run though.
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> On Thu, Dec 17, 2015 at 9:25 PM, arjan tijms <arjan.tijms_at_gmail.com>
>> wrote:
>>
>>> Hi,
>>>
>>> On Thu, Dec 17, 2015 at 7:01 PM, Werner Keil <werner.keil_at_gmail.com>
>>> wrote:
>>>
>>>> Dear All,
>>>>
>>>> A little follow-up. I'll also plan to upload the slides either today or
>>>> over the weekend.
>>>> The app-db example feels like something gets stuck, either the data
>>>> source is no longer accessible or similar. Even adding and removing the app
>>>> to GlassFish 4 did not help..
>>>>
>>>
>>> Unfortunately data sources seem to be a little buggy on GlassFish, at
>>> least embedded ones. java:app doesn't work at all, I encountered some
>>> issues with XA connection pooling, and indeed, data sources stick around
>>> and you need to restart GlassFish :(
>>>
>>> Payara recently fixed this last bug though, see
>>> https://github.com/payara/Payara/pull/565
>>>
>>> A couple of other data source problems are in the associated issue:
>>> https://github.com/payara/Payara/issues/510
>>>
>>> In general, bugs in various servers is part of what causes some
>>> seemingly simple example applications to take up quite a lot of time.
>>>
>>>
>>>
>>>
>>>> One question I'm not entirely sure, if it's applicable was, if vendors
>>>> of JCE implementations were to adopt JSR 375. Maybe it's simply the
>>>> "java.security" package name that created such impression. The only area
>>>> which I brushed answering someone else's question was, that at least in
>>>> production where passwords aren't masked using aliasing the actual password
>>>> store should always be encrypted, too.
>>>>
>>>
>>> Indeed, so password aliasing is as you know on the schedule of this JSR
>>> and I assume this may use JCE, but this is a topic Alex likely knows more
>>> about.
>>>
>>> Btw, the provided examples are all aimed at demonstrating the API
>>> interactions, and the current implementations are as simple as can be. The
>>> data in the various stores is now all unencrypted. Naturally this should
>>> never be done in production.
>>>
>>>
>>>
>>>> Not from Tel Aviv, but the host of Hackergarten Zürich, Oliver Nautsch
>>>> asked based on actual needs we help the current client meet on Java EE 6
>>>> with proprietary extensions to CDI and other frameworks built in-house.
>>>> Taking the "Movie" DB test case
>>>> https://github.com/javaee-security-spec/javaee-security-examples/tree/master/roles-allowed-and-runas
>>>> he hinted, whether it was possible to add a "content aspect" to the
>>>> SecurityContext / RunAs. Say "Manager1" could only manipulate or see movies
>>>> by "Quentin Tarantino" while "Manager2" could only do so for "Joel Coen".
>>>>
>>>
>>> It sounds interesting and a bit like the entity equivalent of row level
>>> security in a SQL DB. I have to leave it to Alex to answer anything
>>> definite here about this being in scope of this JSR.
>>>
>>> As mentioned by Alex, an important goal of the JSR is to grab the really
>>> low hanging fruit; the obvious things that for some reason or the other
>>> never have been standardised before. It's an open question if we'll be able
>>> to get to the more advanced things.
>>>
>>>
>>>>
>>>> Actually looking at the large PDF Alex presented at least in Paris (and
>>>> probably also London or JavaOne?) this sounds like involving "Dynamic Role
>>>> Mapping" with roles like "EDIT_ACCOUNTS", "CLOSE_ACCOUNT", etc. If this was
>>>> done on a fine grained level like "EDIT_TARANTINO_FILMS" vs.
>>>> "EDIT_COEN_FILMS" just to give an example (or say "VIEW_ADULT_FILMS" based
>>>> on a person's age;-) it might go in the direction of what the client uses
>>>> here and Oliver suggested.
>>>>
>>>
>>> In case of the row level security equivalent, my guess would be that
>>> (JPA) entities have to support some notion of security constraints; a kind
>>> of cross between bean validation and @RolesAllowed. I.e. a roles allowed
>>> placed on a "value", and the entity manager checking this for various
>>> operations.
>>>
>>> Fine grained roles could be done by simply giving user "Manager1" the
>>> role "EDIT_TARANTINO_FILMS", etc, right?
>>>
>>> Or is "Manager1" a role name here, and do you mean that someone with
>>> role "Manager1" should also get role "EDIT_TARANTINO_FILMS"? If that's the
>>> case it would more be a matter of (standardised) group to role mapping
>>> perhaps.
>>>
>>> Dynamic role mapping, where for every authorization decision roles are
>>> dynamically evaluated is in fact today possible via JACC. A (custom) JACC
>>> provider is called every time @RolesAllowed and access to a URL is
>>> evaluated and can do things like taking time into account.
>>>
>>> JEUS has a native authorization system that is very JACC like. They have
>>> some interested added concepts, like that in a role mapping you have the
>>> tuple {role name, action, class name}.
>>>
>>> See
>>> https://translate.google.com/translate?&u=http%3A%2F%2Ftechnet.tmaxsoft.com%2Fupload%2Fdownload%2Fonline%2Fjeus%2Fpver-20150722-000001%2Fsecurity%2Fchapter_security_system_API_programming.html
>>>
>>> Taking age into account is more difficult, since the authorisation
>>> system has to know where it can find the age of the caller. For the
>>> proposed new annotation that takes an EL expression this should be quite
>>> doable (you pass the age in), but for web.xml security constraints this is
>>> more difficult.
>>>
>>> But these are all good points for the authorization epic of this JSR ;)
>>>
>>>
>>>
>>>
>>>
>>>>
>>>> Kind Regards,
>>>> Werner
>>>>
>>>> On Thu, Dec 17, 2015 at 5:24 AM, Werner Keil <werner.keil_at_gmail.com>
>>>> wrote:
>>>>
>>>>> All,
>>>>>
>>>>> Had a great talk yesterday. At least 50-70 people (guess DevoXX Be
>>>>> probably had more, not sure about FR or Uk?) in a cinema very similar to
>>>>> Antwerp ;-)
>>>>>
>>>>> I invited those interested to join the mailing list or Github. Right
>>>>> before my Session was one on the value of Open Source which was a good
>>>>> introduction. Will Post slides on Slideshare. Thanks everyone especially
>>>>> Arjan.
>>>>>
>>>>> Regards,
>>>>> Werner
>>>>> Am 15.12.2015 18:48 schrieb "arjan tijms" <arjan.tijms_at_gmail.com>:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Another update: I finally came around to implementing an experimental
>>>>>> version of the simplified SAM.
>>>>>>
>>>>>> This version is based on the HttpServerAuthModule that was used in
>>>>>> several examples before, and which in turn was based on the one from
>>>>>> OmniSecurity.
>>>>>>
>>>>>> The difference is that instead of a base class, it's now an interface
>>>>>> (as previously discussed). It closely follows the methods of a SAM, but the
>>>>>> type implementing it is no longer a SAM itself.
>>>>>>
>>>>>> For now I've defined the interface as follows:
>>>>>>
>>>>>> public interface HttpAuthenticationMechanism {
>>>>>>
>>>>>> AuthStatus validateRequest(HttpServletRequest request,
>>>>>> HttpServletResponse response, HttpMsgContext httpMessageContext) throws
>>>>>> AuthException;
>>>>>>
>>>>>> default AuthStatus secureResponse(HttpServletRequest request,
>>>>>> HttpServletResponse response, HttpMsgContext httpMessageContext) throws
>>>>>> AuthException {
>>>>>> return SEND_SUCCESS;
>>>>>> }
>>>>>>
>>>>>> default void cleanSubject(HttpServletRequest request,
>>>>>> HttpServletResponse response, HttpMsgContext httpMessageContext) {
>>>>>> httpMessageContext.cleanClientSubject();
>>>>>> }
>>>>>>
>>>>>> }
>>>>>>
>>>>>> See
>>>>>> https://github.com/arjantijms/mechanism-to-store-x/blob/master/jsr375/src/main/java/javax/security/authenticationmechanism/http/HttpAuthenticationMechanism.java
>>>>>>
>>>>>>
>>>>>> The JSR 375 CDI extension scans for the one and only implementation
>>>>>> of HttpAuthenticationMechanism, and if found installs a bridge SAM for it
>>>>>> that calls this implementation for each method: E.g. for validateRequest it
>>>>>> looks like this:
>>>>>>
>>>>>> public AuthStatus validateRequest(MessageInfo messageInfo, Subject
>>>>>> clientSubject, Subject serviceSubject) throws AuthException {
>>>>>> HttpMsgContext msgContext = new HttpMsgContext(handler, options,
>>>>>> messageInfo, clientSubject);
>>>>>> return CDI.current()
>>>>>> .select(HttpAuthenticationMechanism.class).get()
>>>>>> .validateRequest(msgContext.getRequest(),
>>>>>> msgContext.getResponse(), msgContext);
>>>>>> }
>>>>>>
>>>>>> Just like the identity store, applications can now use a "sam" by
>>>>>> only having an implementation of HttpAuthenticationMechanism on their
>>>>>> classpath. The code now looks much simpler too. E.g. the example SAM used
>>>>>> before is simplified into this:
>>>>>>
>>>>>> @RequestScoped
>>>>>> public class TestAuthenticationMechanism implements
>>>>>> HttpAuthenticationMechanism {
>>>>>>
>>>>>> @Inject
>>>>>> private IdentityStore identityStore;
>>>>>>
>>>>>> @Override
>>>>>> public AuthStatus validateRequest(HttpServletRequest request,
>>>>>> HttpServletResponse response, HttpMsgContext httpMessageContext) throws
>>>>>> AuthException {
>>>>>>
>>>>>> if (request.getParameter("name") != null &&
>>>>>> request.getParameter("password") != null) {
>>>>>>
>>>>>> // Get the (caller) name and password from the request
>>>>>> // NOTE: This is for the smallest possible example only.
>>>>>> In practice
>>>>>> // putting the password in a request query parameter is
>>>>>> highly
>>>>>> // insecure
>>>>>> String name = request.getParameter("name");
>>>>>> Password password = new
>>>>>> Password(request.getParameter("password"));
>>>>>>
>>>>>> // Delegate the {credentials in -> identity data out}
>>>>>> function to
>>>>>> // the Identity Store
>>>>>> CredentialValidationResult result =
>>>>>> identityStore.validate(
>>>>>> new UsernamePasswordCredential(name, password));
>>>>>>
>>>>>> if (result.getStatus() == VALID) {
>>>>>> // Communicate the details of the authenticated user
>>>>>> to the
>>>>>> // container. In many cases the underlying handler
>>>>>> will just store the details
>>>>>> // and the container will actually handle the login
>>>>>> after we return from
>>>>>> // this method.
>>>>>> return httpMessageContext.notifyContainerAboutLogin(
>>>>>> result.getCallerName(), result.getCallerGroups());
>>>>>> } else {
>>>>>> throw new AuthException("Login failed");
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> return httpMessageContext.doNothing();
>>>>>> }
>>>>>>
>>>>>> }
>>>>>>
>>>>>> See:
>>>>>> https://github.com/arjantijms/mechanism-to-store-x/blob/master/app-db/src/main/java/test/TestAuthenticationMechanism.java
>>>>>>
>>>>>> One partially unsolved problem, which I happen to have discussed with
>>>>>> Ron Monzillo some time ago, is how module options should neatly arrive in
>>>>>> this CDI enabled SAM. Currently they can be obtained from the
>>>>>> HttpMsgContext. Ideally though, you may want to inject them and do
>>>>>> something in the @PostConstruct method.
>>>>>>
>>>>>> But as those module options are per SAM, and there can be multiple
>>>>>> SAMs, even of the same class type, I was struggling a little on how to
>>>>>> support that.
>>>>>>
>>>>>> CDI itself has something like this with their Bean<T>, and they use a
>>>>>> unique ID for that that is typically set to just the classname, but can be
>>>>>> more eloborate if needed. Typically the values of constructor parameters
>>>>>> are included if the Bean<T> has one. See e.g.
>>>>>> https://github.com/javaserverfaces/mojarra/blob/master/jsf-ri/src/main/java/com/sun/faces/cdi/CdiProducer.java#L97
>>>>>>
>>>>>> Kind regards,
>>>>>> Arjan Tijms
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Mon, Dec 14, 2015 at 11:43 AM, Werner Keil <werner.keil_at_gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Thanks for the update. I will try it in WildFly at some point, but
>>>>>>> especially the current client and environment (where especially some ideas
>>>>>>> in the JSR like "roles allowed" found here
>>>>>>> https://github.com/javaee-security-spec/javaee-security-examples
>>>>>>> would be of interest in theory) are not even able to use WildFly or Java EE
>>>>>>> 7 and probably won't be for another decade, so it is not so urgent before
>>>>>>> codemotion.
>>>>>>>
>>>>>>> Kind Regards,
>>>>>>>
>>>>>>> Werner Keil
>>>>>>>
>>>>>>> On Mon, Dec 14, 2015 at 11:21 AM, arjan tijms <arjan.tijms_at_gmail.com
>>>>>>> > wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On Mon, Dec 14, 2015 at 12:25 AM, Werner Keil <
>>>>>>>> werner.keil_at_gmail.com> wrote:
>>>>>>>>
>>>>>>>>> It works well in Glassfish 4, Wildfly 10 did not,
>>>>>>>>
>>>>>>>> [...]
>>>>>>>>
>>>>>>>> Yes, I did not modify it
>>>>>>>>>
>>>>>>>>
>>>>>>>> Again a life "proof" of how important it is that WildFly does not
>>>>>>>> require the modification ;)
>>>>>>>>
>>>>>>>> You're not the first one to fall into this. Quite a few people
>>>>>>>> think it doesn't work on JBoss, since this modification is so non-obvious.
>>>>>>>>
>>>>>>>> Or the modification is done once, and then later a new install of
>>>>>>>> JBoss (WildFly) is done and the modification is forgotten again (this
>>>>>>>> happens all the time over at the Java EE 7 samples project for the CI).
>>>>>>>>
>>>>>>>> Kind regards,
>>>>>>>> Arjan Tijms
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>
>>>
>>
>