jakarta-eejaspic

When using JASPIC for authentication, is web.xml still relevant in terms of authentication?


It's been a loooooong time since I've done JASPIC work.

I have a web.xml that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>service-broker-related-resources</web-resource-name>
      <url-pattern>/v2/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>emcc</role-name>
    </auth-constraint>
  </security-constraint>

  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Frob Service Broker</realm-name>
  </login-config>

  <security-role>
    <role-name>emcc</role-name>
  </security-role>

</web-app>

I have a Server Authentication Module (SAM) set up and installed as well. It is mentioned in my glassfish-web.xml like this:

<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app httpservlet-security-provider="emccSAM">

My SAM works fine.

In fact, it works a little too well! It is intercepting all requests, not just the ones identified by the <url-pattern> of /v2/*. That initially surprised me.

But then when I think hard about this, I think this makes a certain amount of sense: the SAM is now in charge of authentication, not the container, really.

So is the web.xml now essentially irrelevant?

Then I think some more about it and clearly it's relevant, because its contents also say what to do after authentication has taken place, i.e. if the user authenticated successfully through the SAM, now check to see if she has the emcc role. If she does not, and, presumably, the request starts with /v2/, then we boot her out. If she does not, and, presumably, the request starts with anything else, then we let her in.

So is it expected behavior, then, that my SAM has to effectively decide all on its own whether the incoming request deserves authentication? I would expect that my SAM would be triggered "normally", i.e. only when someone attempts to access a URI that requires authentication, as described by the <security-constraint>.

It might be worth noting that the only servlet in play is the one installed by default when a JAX-RS Application class is annotated with @ApplicationPath("/v2").


Solution

  • A SAM is indeed fully in charge of authentication. It may respect the declarative configuration, but is not required to. It could even perform authorization of Servlet requests on its own entirely (although doing so would fall well outside its contract's scope).

    As per § 3.8.3 of the JASPIC spec, it is mandated that validateRequest be invoked on the configured ServerAuthContext (hence its single encapsulated SAM as well, in this case) "on every request that satisfies the corresponding connection requirements".

    If a SAM wishes to know whether a Servlet endpoint should, descriptor- or annotation-wise, be considered "protected", it may call isMandatory on the request MessagePolicy argument relayed to it at initialization time, or probe, at message authentication time, the MessageInfo argument's map for presence of the "javax.security.auth.message.MessagePolicy.isMandatory" key and a mapped value equal to Boolean.valueOf(value).booleanValue() == true (spec § 3.8.1.1).

    Last but not least -- are declarative security constraints irrelevant in terms of authorization? First of all I am unsure whether the various specs are okay with a SAM assigning undeclared roles. That aside, I haven't ever tried this, so I can only guess and provide a vague answer at this point. My take on this is that it would be more or less the same as with the authentication provider's case. You are essentially taking the responsibility of configuring the provider away from the AS, hence you must somehow compensate, i.e., provide alternative configuration interfaces. Say authorization is managed by some JACC provider. If it's the default, AS-provided one, it would, in the absence of declarative security constraints, fail to acknowledge the fact that a caller needs to be in the "emcc" role in order to access the /v2/* collection of resources, i.e., have an equivalent WebRoleRefPermission mapped to their Principal; thus, Policy::implies would always grant access. But a handcrafted provider, like a custom SAM, could retrieve that knowledge from elsewhere, such that @RolesAllowed and friends delegating to it still work. After all it is not as if the Java EE security model -- including the "plumbing" of populating Subjects, binding them to requests' threads' AccessControlContexts, handling Subject::doAs(Privileged) calls, and so forth -- became irrelevant, only how the provider obtains the constraints has. Naturally, the question whether your requirements justify the hassle, remains.