I'm (still) studying JASPIC, doing some experiments by simple project: this one. When I call a protected resources ServerAuthModule
checks credentials via validateRequest
and returns AuthStatus.SUCCESS
. HTTP response is 200 but it is empty. I use these two curl
commands to test:
curl -H "Content-Type: application/json" -X POST -d '{"username":"xxx","password":"xxx"}' http://localhost:8080/JaspicWeb/services/user/login
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzE0NzE1ODcsInN1YiI6InVzZXJBIn0.Gyf7w2192vlz3uSwjwtf8z1p9n9k3IqtQMQrubA7oYI" -X GET http://localhost:8080/JaspicWeb/services/user/userA
The first command is to get the token used in the second one. I'm using Jaspic with Wildfly10 and RestEasy.
Update:
I updated the linked project. Now it is a full working Jaspic
example.
The SAM's CallbackHandler
is the cause of your troubles.
First it.jaspic.sec.TokenConfigProvider
disregards the handler passed to it by the runtime:
public ServerAuthConfig getServerAuthConfig(String layer, String appContext, CallbackHandler handler) throws AuthException {
return serverAuthConfig;
}
Then it.jaspic.sec.TokenServerConfig
uses its own handler, which basically does nothing:
public TokenServerConfig() throws AuthException {
// ...
handler = new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
// just logs its arguments
}
};
}
Consequently, it.jaspic.sec.TokenSAM#validateRequest
is unable to communicate the caller's identity to the runtime. Since it still erroneously returns AuthStatus.SUCCESS
though, it is pretty much undefined behaviour from that point on, at least as far as JASPIC is concerned. It is, amusingly, as if the Servlet container were trying to keep both parties happy in this case, by honoring both the SAM's AuthStatus
that suggests a successful authentication message exchange, on the one hand, as well as the application's <security-constraint>
on the other. Admittedly, a 401
, 403
, or perhaps better yet, a 500
response--indicative of an authentication mechanism not obeying its contract--might have been less confusing.
The obvious solution is to pass the runtime-provided handler to the SAM. The API clearly doesn't help much, but for the single message layer/single app/single authentication mechanism use case, it should be sufficient to just lazily instantiate the ServerAuthConfig
with the handler, when it is first requested by the runtime via a getServerAuthConfig
invocation:
public synchronized ServerAuthConfig getServerAuthConfig(String layer, String appContext, CallbackHandler handler) {
if (serverAuthConfig == null) {
serverAuthConfig = new TokenServerConfig(handler);
}
return serverAuthConfig;
}
And, of course, the new constructor called above (which only has to store the handler argument) has to be introduced into it.jaspic.sec.TokenServerConfig
.
Those two changes should render the /services/user/userA
endpoint accessible.