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

[jsr375-experts] Re: Authorization mechanism

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Wed, 24 Aug 2016 20:40:59 +0200

Hi,

In the month between the proposal of the idea and the published POC,
feedback has been generally positive till thus far, so I think it would be
a good idea to proceed with this.

I got some really good feedback from Guillermo off list as well as from a
variety of other users.

Overall, the concept of being able to influence the authorization rules,
specifically for the so-called pre-dispatch decision made by the Servlet
container (i.e. for determining access to a URL) was well received.

v.s. JACC, the JSR 375 authorization mechanism would offer the following
benefits:

* Not having to install something inside the application server in a
proprietary way (this can be quite demanding on the developer, see e.g. the
steps needed for Liberty:
http://www.ibm.com/support/knowledgecenter/en/SSAW57_liberty/com.ibm.websphere.wlp.nd.doc/ae/twlp_developing_jacc_auth_provider.html
and
http://www.ibm.com/support/knowledgecenter/SSAW57_liberty/com.ibm.websphere.wlp.nd.doc/ae/twlp_feat_example.html
)

* Not having to re-implement the entire Java EE authorization rule engine
from scratch for every small addition (this is really demanding on the
developer, see e.g. the code needed for that here:
http://arjan-tijms.omnifaces.org/2015/03/java-ee-authorization-jacc-revisited.html
)

* Having custom authorization rules per application instead of for the
entire server (e.g. adding a rule for "manager role valid between office
hours" is often only applicable for a single application, not for all apps
on a single server)

* CDI based, allowing to use interceptors, decorators, injection of
services and what have you


To move the POC to a proposal, some things should still be decided:

*** Naming ***

AuthorizationMechanism, AuthorizationModule, something else?


*** Way to invoke custom rules ***

In my POC I used a Bean implementing an interface with various methods
being called (1 method for each moment). There are various alternatives
possible, like throwing CDI events, or having annotated methods or classes
where the annotation would indicate in some way at what moment of the
authorization process the module wishes to intervene.

In broad lines the two major moments are:

* Before the authentication mechanism is called (the user is guaranteed not
to be authenticated at this point)
* After the authentication mechanism is called (user may be authenticated
here)

If the BEFORE AUTHENTICATION outcome is that access is rejected, it means
that authentication is now mandatory, and after authentication has been
completed the authorization mechanism/module will be called again.

For the BEFORE AUTHENTICATION moment the following sub moments would be
possible:

* Before the excluded check: before check if no-one can access resource
* Before the unchecked check (==after excluded check): before check if
resource is freely accessible to all
* After the unchecked check

For the AFTER AUTHENTICATION moment the following sub moments would be
possible:

* Before the excluded check
* Before the unchecked check (==after excluded check)
* Before the any authenticated user check (==after unchecked check): before
check if resource can be accessed by anyone who has been authenticated,
regardless of the roles that caller has
* Before the role check (==after any authenticated user check): before
check if resource can be accessed via role caller has
* After the role check

Using method names this would require about 9 methods. An example for the
BEFORE AUTHENTICATION moments:

    default Boolean preAuthenticatePreAuthorize(Permission
requestedPermission, SecurityConstraints securityConstraints) {
        return null;
    }

    default Boolean preAuthenticatePreAuthorizeByRole(Permission
requestedPermission, SecurityConstraints securityConstraints) {
        return null;
    }


An alternative for the name pattern could
be: onBeforeContainerRulesAuthorization (suggested by Guillermo)

Instead of fixed names, each of the 9 moments could be assigned a priority
level (integer number), and general methods could declare at which priority
they like to intercept, e.g.

@AuthorizationMechanism(priority = BEFORE_AUTHENTICATION_BEFORE_EXCLUDED -
1)
public class Something implements AuthorizationRule {

    Boolean checkPermissions(Permission requestedPermission,
SecurityConstraints securityConstraints) {
         return null;
    }
}

@AuthorizationMechanism(priority = BEFORE_AUTHENTICATION_BEFORE_ROLE - 1)
public class SomethingElse implements AuthorizationRule {

    Boolean checkPermissions(Permission requestedPermission,
SecurityConstraints securityConstraints) {
         return null;
    }
}

Using priorities would shift the naming of methods to the naming of
constants of integer values.

Yet another option; the default rules are implemented by a build-in CDI
bean with methods like isExcluded, isUnchecked, and hasAccessViaRole, and
in order to provide the customisation an application has to enable a CDI
decorator. That way it can make the before / after decision by simply doing
what it wants to do before or after calling the decorated bean.

There are probably a lot of other options still.



*** Return type ***

Depending on what variant is chosen or suggested above, the custom method
would need a return type. The POC uses [true, false, null]. Here Guillermo
suggested to use an enum with values [ALLOW, DENY, ABSTAIN].


*** Multiple authorization mechanisms ***

Especially with events, but also with the other options, we could have
multiple rules for the same decision. The question is how to combine
various outcomes. Some options are: all custom rules must ALLOW, first rule
to ALLOW grants called access, first rule to DENY rejects access, etc.

Just as with the multi-identity store proposal, if we go for this we'd
likely want to have a default way to combine outcomes, but allow the user
to plug-in a new way.

It may be a good idea to do the multi authorization mechanisms at a later
stage and focus on the single case first, but this too depends on what
approach is chosen.

Thoughts?

Kind regards,
Arjan Tijms




















On Thu, Aug 18, 2016 at 4:37 PM, Rudy De Busscher <rdebusscher_at_gmail.com>
wrote:

> True, although in practice almost nobody writes these since it's far too
>> much work for even the simplest of things (you basically have to code up
>> all things that you would normally assume a container would do), and a
>> portable application can't easily use it, since you need to install the
>> JACC module into your server somehow in some not rarely obscure way.
>
>
> That is a good reason to put it in Java EE Security API.
>
> Rudy
>
> On 18 August 2016 at 12:17, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>
>> Hi Rudy,
>>
>> Thanks for your reply ;) See comments inline below:
>>
>> On Thu, Aug 18, 2016 at 11:29 AM, Rudy De Busscher <rdebusscher_at_gmail.com
>> > wrote:
>>
>>> Arjan,
>>>
>>> I like the idea and I think it can be quite important for a lot of
>>> projects.
>>>
>>> It can be used to define the rules somewhere else and not in the
>>> web.xml. For example when you have an application with 100 screens and 10
>>> user groups, the config within web.xml becomes a burden.
>>>
>>
>> Hmmm, indeed, that would be another rather innovative (for Java EE)
>> approach ;)
>>
>> The authorization module/mechanism has access to the constraints/rules
>> parsed from web.xml and annotations, but it of course doesn't have to use
>> these or doesn't have to use these exclusively.
>>
>> In short, simply having a hook available for developers would open up a
>> world of new possibilities for both developers as well as extension
>> libraries.
>>
>>
>>
>>> So I see it not only as a way of dynamical defining the authorization
>>> but also as an SPI for the authorization rules.
>>>
>>
>> Indeed ;)
>>
>>
>>
>>> The question remains then if we need to foresee it in the Java EE
>>> Security API or that it needs to be included in (a next version) JACC?
>>>
>>
>> This particular approach is too high level for JACC I think which
>> operates at a much lower level. Just as the identity store and
>> authentication mechanism that we defined here were too high level for
>> JASPIC.
>>
>> This was a question though we also struggled with earlier. Do we start a
>> JSR 375 at all, since ultimately everything we do is either authentication
>> or authorization, and JASPIC resp. JACC already do that. At long last it
>> was (more or less) decided to keep JASPIC low level, and build the higher
>> level CDI based and Servlet specific types in JSR 375.
>>
>>
>>
>>> Or that we need to specify something because with a custom JACC module
>>> you can achieve it already today.
>>>
>>
>> True, although in practice almost nobody writes these since it's far too
>> much work for even the simplest of things (you basically have to code up
>> all things that you would normally assume a container would do), and a
>> portable application can't easily use it, since you need to install the
>> JACC module into your server somehow in some not rarely obscure way.
>>
>> With this proposal, a developer doesn't have to write hundreds of lines
>> of code and implement a state machine, life cycle manager, configuration
>> collector etc, but only a single method that asks for an outcome. And most
>> importantly (as per the main goal of JSR 375) nothing application server
>> specific would have to be done.
>>
>> The new interface would also technically not be tied strongly to JACC.
>> It's just a CDI bean that gets consulted by whatever system when it want to
>> make an authorization decision. Of course for Java EE and specifically for
>> the RI and Payara the no brainer way to implement it would be via a JACC
>> provider that's by default installed (just as the Soteria main jar is by
>> default installed).
>>
>> It would greatly help though if JACC got a MR where it allowed a classic
>> JACC provider to be installed in a per web app fashion. That would greatly
>> simplify matters for vendors implementing JSR 375 and for to test Soteria
>> on different servers. I already send a proposal for that to the JACC list.
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>
>>
>>
>>>
>>> best regards
>>> Rudy
>>>
>>>
>>> On 25 July 2016 at 18:37, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>>>
>>>> Hi,
>>>>
>>>> Up till now we've mostly been looking at the authentication epic, and
>>>> even though that's not entirely finished yet (the multi identity store
>>>> proposal and various multi authentication mechanism proposals are still
>>>> open), it may be a good idea to start looking at simplifying authorization.
>>>>
>>>> To that end I've been prototyping an initial proposal for an
>>>> authorization mechanism or authorization module (name still TBD).
>>>>
>>>> For the long story: http://arjan-tijms.omni
>>>> faces.org/2016/07/simplified-custom-authorization-rules.html
>>>>
>>>> Shorter story:
>>>>
>>>> An application provided CDI bean that implements the
>>>> AuthorizationMechanism interface, with various methods that are called by
>>>> the container's authorization code (policy) at various moments.
>>>>
>>>> E.g.
>>>>
>>>> @ApplicationScoped
>>>> public class CustomAuthorizationMechanism implements
>>>> AuthorizationMechanism {
>>>>
>>>> @Override
>>>> public Boolean postAuthenticatePreAuthorizeByRole(Permission
>>>> requestedPermission, Caller caller, SecurityConstraints
>>>> securityConstraints) {
>>>>
>>>> return getRequiredRoles(securityConst
>>>> raints.getPerRolePermissions(), requestedPermission)
>>>> .stream()
>>>> .anyMatch(role -> isInRole(caller.getCallerPrincipal().getName(),
>>>> role));
>>>> }
>>>> }
>>>>
>>>> Here:
>>>>
>>>> requestedPermission - the permission being asked for, e.g. "access
>>>> /foo/bar.xhtml using GET"
>>>> caller - the caller's authentication related data, the caller
>>>> principal, the roles, and the raw other principals
>>>> securityConstraints - the constraints as parsed from web.xml (and
>>>> corresponding annotations) as well as from EJB's ejb-jar.xml (and
>>>> corresponding annotations)
>>>>
>>>> Return values:
>>>>
>>>> null - no decision, let default algorithm handle the permission
>>>> true - requested permission granted
>>>> false - requested permission not granted
>>>>
>>>> In the example above "isInRole" is a custom method using whatever logic
>>>> the application needs to determine if the caller has a given role.
>>>>
>>>> This authorization mechanism is called to determine access to URLs, as
>>>> well as for determining the outcome of HttpServletRequest.isUserInRole,
>>>> @RolesAllowed, and of course JSR 375's own future
>>>> SecurityContext.isCallerInRole.
>>>>
>>>> Open questions are e.g. naming; authorization mechanism vs
>>>> authorization module? and using methods vs events?
>>>>
>>>> mechanism and methods are closer to what authentication is using, but
>>>> here module and events may look more natural.
>>>>
>>>> Thoughts?
>>>>
>>>> Kind regards,
>>>> Arjan Tijms
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>
>