Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [es-dev] User principal and role check consistency between specs

Hi,

I just remembered WebSocket also provides a getUserPrincipal method, ony useful when running on a Servlet container and which could also be deprecated.

El lun., 25 jun. 2018 a las 0:27, arjan tijms (<arjan.tijms@xxxxxxxxx>) escribió:
Hi,

On Sun, Jun 24, 2018 at 4:28 PM Guillermo González de Agüero <z06.guillermo@xxxxxxxxx> wrote:
Servlet, JAX-WS and EJB behaviour is theoretically controlled by JACC.

This is indeed the case. Basically all specs in Java EE are united by this "invisible backbone", where JACC is indeed basically the controller of. JASPIC is the only standard SPI in Java EE that can put something into this backbone in an official way.

That's basically why by 'just' using JASPIC, EE 7 security was able to be automatically compatible with Servlet, EJB, etc.
 
JAX-WS should inherit the Servlet rules when implemented on top of them (which is not mandatory).

JAX-WS can use either Servlet or EJB as an endpoint, but in case of JAX-WS there's actually the SOAP profile of JASPIC that comes into play. EE Security has ignored that profile for now. I'm not a super big SOAP expert, but I think different kinds of authentication mechanisms for SOAP are rare. SOAP has its own WSS security, which means that there's essentially a single standard authentication mechanism and little need to ever replace that. In Payara/GlassFish/Metro that is com.sun.xml.wss.provider.ServerSecurityAuthModule. 

However, that authentication mechanism does inject the authenticated identity into the same backbone again (using JASPIC, or in GF/Payara its predecessor JAuth), so if you inject a JAX-WS endpoint with the EE security context, you get the correct identity again.
True, I forgot the JAX-WS profile.


 
But Security has always been difficult on Java EE and so users have relied on a lot of home-grown solutions, like overriding HttpServletRequest or javax.ws.rs.core.SecurityContext methods to control the caller identity. That approach presents the issue that the identity is not controlled by the container and thus not propagated between components.

Indeed, in that case the wrapper HttpServletRequest would not draw its data from this backbone and only callers of HttpServletRequest#getUserPrinciple would see that principle.
Interestingly, GlassFish/Payara propagates the changed Principal to JACC [1].

 

The "is caller in role" methods can also be problematic. Imagine the following situations:
- On a Servlet based JAX-RS resource/JAX-WS service, with a HttpServletRequestWrapper that overrides the getUserPrincipal()/isUserInRole() methods might return different results than the javax.ws.rs.core.SecurityContext and WebServiceContext equivalent methods.
- On an EJB based JAX-RS resource, with a custom javax.ws.rs.core.SecurityContext overriding the getUserPrincipal()/isUserInRole() methods, EJBContext might return different results that SecurityContext.

Indeed, doing custom security by overriding the objects where you query the roles will always lead to inconsistencies. You really have to inject the security data into that backbone to be consistent. This is what people sometimes don't really get.

 
- In any case, it's unspecified where CDI takes its injectable Principal from [2].

Well, it should logically be taken from this same backbone again. But CDI implementations such as Weld do require containers to implement a container specific SPI for that, as there wasn't any other API available before EE Security.

 
- Things like @RolesAllowed and Servlet security constraints won't work with the "dynamic" roles.

Not 100% sure what you mean here. Dynamic roles as implemented by JACC providers do work with the EJB interceptors behind @RolesAllowed, and Servlet security constraints, at least they do in a full Java EE Server (which *must* use JACC for these).
I actually meant wrapped "isUserInRole()" methods, which is what people do nowadays.
 
 

In addition to that problems, there's no guarantee that all the "get caller principal" methods will return the same object. The former JSR 375 EG couldn't agree to return the user defined Principal (via JASPIC) as the caller principal due to some shortcomings in WebLogic.

For the sake of getting the spec released in that timeframe with Will being the WebLogic security architect as well, we indeed had to compromise there, although the getPrincipalsByType should be usable here.

For the next version of JASPIC I'd really like to close the gap that JASPIC left open here (this is where it says that the container is free to return another type, but that it must be possible to configure the container to return the right type, but then doesn't say how to configure this).
That would work for Servlet and JAX-WS, which are directly affected by JASPIC, but being pedantic, what prevents e.g. JAX-RS to return a wrapped Principal or just a different representation? It's reasonable to expect JAX-RS to delegate to HttpServletRequest#getUserPrincipal (which in turn, could have been wrapped to return a different Principal than the one provided to JASPIC), but I don't think the spec mandates it. The JAX-RS implementation might be from a different vendor than the rest of the server and have a special behaviour.


 
To improve this situation, my personal take on this is we should push other specs to:
- Servlet: when there's a JSR375 implementation on the classpath, login must be done via an HttpAuthenticationMechanism.

For the isCallerInRole etc consistency this wouldn't be strictly needed. Login/authentication via proprietary mechanisms (like the Tomcat Authenticator) already injects into the same backbone that JASPIC also injects into, and everything basically works.
Soteria in fact delegates to HttpServletRequest to get the user principal [2], which isn't really safe since we don't really know what version of the request we'll get from CDI and it might haven been wrapped. I've opened a PR to get the user Principal from the base request [3].

The problem of how to detect the caller Principal from the set of Principals in the Subject is not unknown to you :). IdentityStores always put a CallerPrincipal on the Subject, but nothing prevents HttpAuthenticationMechanisms or "low level" JASPIC modules to put another kind of Principal. Did you have any solution in mind to truly standarize caller/group Prinicpals?



For consistency Servlet could technically model all of its internal authentication mechanisms (FORM, BASIC, CLIENT-CERT) to be JASPIC SAMs. I vaguely recall either Mark from Tomcat or Greg from Jetty mentioning this once. They could do this outside EE.

Within an EE container, Will already opened the doors for implementations being allowed to delegate between the Server build-in or EE Security provided authentication mechanisms. This doesn't matter for the data that javax.security.enterprise.SecurityContext returns. As mentioned above, whether you authenticate using a Servlet container proprietary mechanism or via JASPIC/HttpAuthenticationMechanism, javax.security.enterprise.SecurityContext should always return the same data.
True, that was really a totally unrelated concern which deserves another discussion. Let's leave it there for now.


Still, it would indeed be nice if web.xml's <login-config><auth-method>FORM</auth-method></login-config> and @FormAuthenticationMechanismDefinition in an EE environment would be mandated to use the exact same (EE Security) authentication mechanism. Currently they are going to completely different implementations, although these implementations should work in the same way and have the same outcome.

 
In those cases, users are pointed to customize the
javax.security.enterprise.SecurityContext in order to provide custom behaviour, instead of wrapping the HttpServletRequest. Role checks are done against the SecurityContext (which in turn will delegate to JACC by default).

If -everything- in EE would use javax.security.enterprise.SecurityContext as their primary source for the isCallerInRole query, this could almost work, but I think it's not the best place to do this really. For one, decorating SecurityContext would still be inconsistent then with code using JACC directly. Using JACC directly is rare, but still legal. 

Also, custom JACC plug-ins/extensions would be the dedicated place in EE for custom "authorization behaviour". Currently this is far too difficult to implement for application developers to be of practical use, but this can be made much easier. The proof of concept I did for EE Security 1.0 showed a way, but there was no time left to discuss and polish that for inclusion in 1.0, but it should definitely be on the roadmap for the next version.
The SecurityContext would become a layer on top of JACC, so other specs don't need to worry about low level details. They would just depend on Security API, which then would require JACC, in the same way that it already requires JASPIC.

 
JASPIC should always be mandated, even outside Jakarta EE containers.

Absolutely, the Servlet spec already says that this *should* be used. Basically the only spec change is that *should* has to be changed into *must*. Last time around in the Servlet spec discussions about this we were almost there.

 
- JAX-RS: deprecate javax.ws.rs.core.SecurityContext and strongly recommend users to directly use the Security API. JAX-RS doesn't even have a portable way to define security constraints (Servlet integration is optional). Users will still be able to implement home grown security if they don't want/can't use the Security API.

Definite +100 for this. Several other treads discussed this as well, and this seems to have a majority support. There's just no need to duplicate this in EE and specs in EE are already big enough. Now that some can be trimmed a little they really should.

 
- EJB and JAX-WS: if there are new releases of these specs, they should mandate the security methods to delegate to javax.security.enterprise.SecurityContext. EJB Lite and standalone JAX-WS would be outside this rule. @RolesAllowed checks are done agains SecurityContext.

As mentioned, this would not be absolutely necessary for data consistency, but it would free up some code from having to use proprietary/internal APIs. Jakarta EE itself would be implemented using Jakarta EE itself then (just like Mojarra in Payara for instance uses standard Servlet APIs and doesn't use say Tomcat specific APIs instead)
Exactly, that's my idea. We aren't going to encourage people to implement their own SecurityContext, but having everything security related delegate on the same artifact makes integration from other specs easier, and users have a single point to look into. HttpAuthenticationMechanisms+IdentitiStores are a great layer on top of JASPIC, and the SecurityContext could become part of the new layer on top of JACC.

 
- CDI: deprecate Principal injection and delegate its obtention to SecurityContext#getCallerPrincipal.

+100 here too. The CDI EG and specifically the spec lead wanted to be out of the business of providing built-in beans that are the responsibility of other specs. The Security spec should provide the built-in bean for Principal related things, and the Servlet spec should provide the built-in beans for the Servlet artefacts.

 
We get the follwing benefits from this:
- Every "getCallerPrincipal" method returns the same instance. As of now, there's still no guarantee that the instance will be the one defined by the user. But if we are able to eventually remove the concept of "platform-specific" principal representations, all methods will automatically get the user principal. For the time being, they will at least all return the same representation.

I think for the guarantee that say HttpServletRequest#getUserPrincipal returns the custom principal this is not strictly needed. It should already do that when using JASPIC. See the "custom principal" tests here: https://arjan-tijms.omnifaces.org/2016/12/the-state-of-portable-authentication-in.html

Only WebLogic is failing that one. According to the spec WebLogic *must* be able to be configured to that is doesn't fail this test. But as said, it's not specified how this should be configured, and I wasn't able to figure this out from the WebLogic documentation.
 
- Users who need to do application-managed identities will only need to provide an @Alternative SecurityContext and all security related methods will return consistent results. The identity won't be propagated to the container, but container facilities like @RolesAllowed should still work.

Also as mentioned above, it will be all security related methods except for direct usage of the JACC APIs. Even though it's an option, I'd rather see we make it really, really easy to provide custom JACC rules. This should be as easy, or even easier than providing an @Alternative SecurityContext.
As I mentioned, the usecase is not really to provide a way to fake authorization via alternative SecurityContexts, but to create the highest possible level layer which other specs may directly use in order to get a consistent view of the caller identity.


Kind regards,
Arjan


 
_______________________________________________
es-dev mailing list
es-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/es-dev
_______________________________________________
es-dev mailing list
es-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/es-dev

Back to the top