users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Comments on Current Spec Content (take 3)

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Thu, 23 Feb 2017 16:04:43 +0100

Hi Will,

Some more replies to your comments inline below:


On Fri, Feb 17, 2017 at 7:05 PM, Will Hopkins <will.hopkins_at_oracle.com>
wrote:

>
>> - Is CallerPrincipal a sufficient credential for
>> IdentityStore.getGroupsByCallerPrincipal()? Can it be safely used
>> when there are multiple ID stores configured (since the wrong groups could
>> potentially be returned)?
>>
>>
> This is a good question that we should explore further I think. One the
> one hand, some proprietary solutions have complex principals that contain
> much information to disambiguate callers. This however does hurt the simple
> case when scaling down. In JSR 375 one of the key drivers is that security
> should be simpler to implement and comprehend by application developers.
>
> In especially smaller system, "Peter.Johnson_at_somedomain.com" is enough to
> full distinguish the caller.
>
> Do we want to introduce extra attributes to allow for simple named,
> distinguished names, etc? If they are optional, maybe. I don't know yet.
>
>
> I'm not sure we can always expect names that are as unique as email
> addresses -- often, they are just usernames, like "joe" or "whopkins".
>
> In addition to the ambiguity problem -- which I think is significant -- I
> think there's also a problem in that the API would enable unprivileged code
> to query group memberships for arbitrary users -- all I need to do is
> construct a principal with the name I want to query, then invoke the
> interface. Is there anything that would prevent an application from doing
> that?
>

Well first of all I'm a strong advocate of not having untrusted code
running at all on the server.

A great deal of the Java SE machinery around untrusted code was created for
the situation where a single used downloaded a great deal of untrusted code
(applets) and executed that on a local machine.

In Java EE the reverse is typical; you have your own trusted code running
and you want to protected that against many untrusted users.

If you have untrusted code running in your server, you're already too late
and it's almost a lost battle (IMHO).

Using, again, JACC, but also a variety of proprietary security systems,
it's often already possible to do this very query. And with Interceptors
and Servlet Filters it's already possible to wrap many things, which
additionally gives you access to many more things than just which groups a
principal is in.

That said, we could of course specify that this query is a privileged
operation and if the Java SE security manager is active it should be use to
make that call.

But again, I strongly belief in not running unprivileged code at all, and
if absolutely needed, isolate it in a separate OS process or container and
interact with it via e.g. rest calls.



>
> I had in mind something considerably simpler than what JSR 351 was
> considering -- a new AttributePrincipal type, or perhaps a Credential
> rather than a Principal. The trouble with using Principal is that, for
> attributes, we need both name and value, but Principal only defines Name.
> We'd need to extend the Principal interface for this use case -- or define
> a single, formatted String with an "=" in the middle, which the user would
> have to parse after calling getName(). The problem with using a
> non-Principal type and keeping it in one of the Credential sets is that
> credentials aren't serialized when a Subject is serialized.
>


Well, in the not yet integrated authorization rules prototype I did kinda
use something like this as well; see
https://github.com/arjantijms/cdi-jacc-provider/blob/master/src/main/java/org/omnifaces/jaccprovider/jacc/Caller.java

Maybe we could haul that over first and give it a general attribute map or
so. I'm not sure yet, just thinking out loud,



> This is something we could consider, that might make IdentityStore more
> useful, but I don't have strong feelings about it, and we're probably
> better off keeping things simple.
>

Indeed, if there once was a complete JSR for it the problem space is likely
to be quite complex in general.


Agree; JASPIC took another approach -- an application that registers an
> AuthConfig gets what it wants; the container can't legally override that.
>


Although you can provide a SAM at the container level and the application
does not replace the JASPIC Factory typically.

It may be too late in the process now, but seeing how we could make such
override legal could have a lot of value still.



>
> I'd say for now, and with some reservation, that in the simple case an
> identity store should contain only callers/users that can be uniquely
> defined using the information contained within the CallerPrincipal. In
> other words, "foo_at_bar.com" *must* be unique.
>
> If this is insufficient for a particular application, it may be a matter
> of adding url like parameters to the name string, e.g. "
> foo_at_bar.com?department=xyz&branch=abc". Interpretation of such name is up
> to the identity store implementation and the spec would not have to know
> about it.
>
>
> But if the spec didn't know, that implies non-public contracts between
> IdentityStores and HttpAuthenticationMechanisms -- a nightmare for
> interoperability.
>

I'm not sure if there would be non-public contracts really needed here.
The HttpAuthenticationMechanisms just passes a String to
the IdentityStores. What it does with that is its concern.




> 2) you only return groups to a caller who has presented proof of the right
> to access them (i.e., the login credential).
>

It's not actually the caller who uses or sees the groups, but more the
system operating internally.

If "joe" is unique within a system, and "joe" is authenticated, why would
the internal container code not be allowed to query what groups or roles
"joe" has? This is already what happens now in internal code anyway, and
that internal code is often easier to access by application code than
people likely think.

If "joe" is not unique, then obviously the system architect or developer
should not set up multiple stores relying on that.




> OK, makes sense. I wonder if it would be better to say that aggregation
> must be provided by an IdentityStore implementation, rather than the
> framework.
>

It's technically the handler which does the aggregation, and this handler
can be replaced. I was present at a JUG event where Rudy presented and took
advantage of this option in one of his examples. It looked quite easy and
still very powerful.



We could probably define some additional flags similar to JAAS that would
> provide flexibility in how providers were aggregated.
>

JAAS/PAM style flags were considered before by the EG, but honestly these
are quite complex and hard to understand, and even if you do understand
them well they don't allow you half of the options of Rudy's simple
replaceable handler ;)




>
> It's the same behaviour now, although there was a discussion not the use
> the exact exit codes and constants for them, but use more specific enums
> instead. These enums would then be mapped to the existing JASPIC return
> codes, so they would still imply the same behaviour.
>
>
> So we'll need to define these as part of the spec ...
>

Yes indeed, this is both an open implementation and spec issue.



> Right. It would either need to maintain it's own context -- which the
> legacy calls delegated to -- or figure out what container it was in and
> delegate to that.
>

Figure out the container and delegate to that is somewhat of a viable
approach indeed. This is what I used for my own (now deprecated)
OmniSecurity framework.



> Could we not leave the exact mechanism up to the containers, as is
> currently the case for, e.g., HttpServletRequest.isUserInRole()? I'm
> reluctant to rely on JACC because, as you point out, it's not always
> present/enabled.
>

I understand where you're coming from as WLS is indeed one of the servers
that does not have it enabled (which btw I believe is a spec violation,
just one that the TCK doesn't test for).

Not having a JACC module/provider present should not be a big problem, as
JSR 375 can deliver one as part of the spec.

But I guess a compromise would be to *strongly recommend* that JACC is used
for this (so Soteria will use it for that then), but that ultimately
containers may decide to use their own mechanism for it.

Would that work for you?


> In the ideal case BASIC, FORM, etc are implemented using SAMs I think.
> That's a lower level interface more suited to plain Servlet container than
> the HAM is, which is as mentioned basically a higher level SAM.
>
>
> While I think JASPIC is a natural implementation for those mechanisms, I
> don't think mandating an implementation makes sense -- presumably, the
> externally-visible behavior would not change, so containers should be free
> to do what they like. I was just making sure I understood the implications
> of the statement.
>

I think you understand it correctly ;)

I think it makes practical sense to have those mechanisms being SAMS, so
that there's 1 code path and not 2 for containers. Management interfaces
would only have to query the JASPIC Factory for all mechanisms present, and
in general the entire "two worlds" that JASPIC SAMs and Servlet standard
authentication mechanisms now are would disappear.

Whether we should focus on that now is another question ;)




> Was there a reason for specifying the ability to downcast? For container
> implementations I'm familiar with, that's automatically true, because the
> container simply returns the same principal that was created by the ATN
> mechanism. Have you had cases where doing this was necessary, but not
> possible?
>

Yes certainly., In JBoss it happened quite often that the custom principal
got lost. In GlassFish this too was (and I think still is) the case. Payara
fixed it though in the GlassFish case.

In general "not getting custom principal" is a topic I've seen many times
on different forums and lists throughout the years. Containers are quite
eager with wrapping the principals in their own principal wrappers, and
this not rarely leaks when doing a getUser/CallerPrincipal call.



> Even with that, I believe the language is too restrictive. AFAIK, there is
> no requirement for roles to be represented by groups, even after mapping.
> In the case of WebLogic (and assuming JACC is not in use), role mapping is
> done dynamically at runtime, and roles are distinct from groups. Roles are
> mapped, using a proprietary descriptor, to either user or group principals,
> and, at runtime, the existence of a mapped principal implies the role --
> but the role is not, itself, a group, and is never represented in the
> Subject by a principal of any time.
>

I agree with you there. Indeed, a role does not *have* to be represented by
a group.

In fact I wrote an article about this very topic last year:
http://arjan-tijms.omnifaces.org/2016/07/simplified-custom-authorization-rules.html

This uses the prototype authorization rules proposal, which itself uses
JACC under the cover. So yes, JACC too can do the dynamic mapping or
granting.

The reason why I put that draft text there was to make the connection
between those "things" being called "group" in the identity store and
"role" in the application, and the connection between those.

We should surely rewrite this text to make it less restrictive indeed.

Kind regards,
Arjan Tijms