My web application uses internal web API (simple AJAX requests from a browser as it's the major client) that's eventually supposed to be exposed externally for the 3rd parties. Since the API is and must be protected with the security constraints in web.xml
, a user or a client must be authenticated. Currently, there's a custom form authenticator implemented, it performs some additional checks and actions, and then simply delegates the further authentication processing to the FormAuthenticator
class the custom authenticator is derived from. This works really nice yet, because a user is simply forced to login and pass authentication, and the only client is a web browser.
But FORM authentication is not very suitable for another kinds of clients: let's say an Android client, various 3rd-party clients, etc. Too pass the form authentication they all must simulate the behavior I was looking for in this question: How can I simulate form authentication in Tomcat using JMeter? . After some investigation of the Tomcat source code, I've got an idea that it should be possible to extend the AuthenticatorBase
class to implement own way of authentication (like FormAuthenticator
or BasicAuthenticator.java
do). What I tried to do was:
public final class SimpleAuthenticator extends AuthenticatorBase {
private static final String USERNAME_PARAMETER = "username";
private static final String PASSWORD_PARAMETER = "password";
@Override
protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException {
final Principal principal = request.getUserPrincipal();
final String ssoId = (String) request.getNote(REQ_SSOID_NOTE);
if ( principal != null ) {
if ( ssoId != null ) {
associate(ssoId, request.getSessionInternal(true));
}
return true;
}
if ( ssoId != null && reauthenticateFromSSO(ssoId, request) ) {
return true;
}
final String contextPath = request.getContextPath();
final String requestURI = request.getDecodedRequestURI();
final boolean login = requestURI.equals(contextPath + "/authenticate");
if ( !login ) {
response.sendError(SC_FORBIDDEN);
return false;
}
final String username = request.getParameter(USERNAME_PARAMETER);
final String password = request.getParameter(PASSWORD_PARAMETER);
final Realm realm = context.getRealm();
final Principal authenticatedUserPrincipal = realm.authenticate(username, password);
if ( authenticatedUserPrincipal == null ) {
response.sendError(SC_UNAUTHORIZED);
return false;
}
register(request, response, authenticatedUserPrincipal, "SIMPLE", username, password);
return true;
}
}
Simply speaking, I'd like to use something like /%CONTEXT_PATH%/authenticate?username=%USERNAME%&password=%PASSWORD%
to authenticate a user with my custom non-form SimpleAuthenticator
. Not really sure if BasicAuthentication
would be better for such a case, but I got the following issues with the example above:
- Tomcat allows to specify multiple
Valve
's incontext.xml
. If the another authenticator is added to thecontext.xml
file, then every secured resource is processed with every authenticator. (In principle, I understand why it happens, but can they be separated for different resources?) /%CONTEXT_PATH%/authenticate
is not accessible (HTTP 404). (Not clear yet knowing that/j_security_check
is simulated somehow.)- I couldn't find a way to specify multiple authentication schemes in Tomcat, so "old" web browser client could still use
FormAuthenticator
(like it does today), but the "light-weight" clients could use that simplified authentication I tried to implement withSimpleAuthenticator
. (Don't even know if it's possible -- that is the core) - As far as I understood the servlet specification, only one
login-config
is allowed for entire web-application. (Well, should I have use another web app to provide the API?) - I saw some mentions to implement custom authentication via
Filter
, but if it's possible -- I'd like to keep the authenticator module separately in a single place (like it already is and confirmed with Tomcat: Custom form authenicator in a web application, not as a stand-alone JAR module. Possible? ). However I'm very ok to review the general concept I use from scratch.
I suspect that I'm doing a quite wrong thing and have total understanding, but I don't believe that there's no way to implement multiple authentication schemes in Tomcat.
Is there any way to provide multiple authentication schemes to extract the authentication out of FormAuthetication
(for light-weight clients)? Your help would be really very appreciated. Thanks in advance.