apachetomcatauthorizationmod-jk

Pass username and client certificate from apache to tomcat using mod_jk


I want to authenticate web services either by ssl certificate (aimed at automatisms) or openid (aimed at people, I am using auth0 as a provider). The web services run in a tomcat container, which is behind an apache web server, using jk. The web server already authenticates the user using auth0 (an using mod_auth_openidc) for other paths, and only available through https. I also have a database which currently maps usernames provided by auth0 to roles (used for authorization in apache).

I would like to have the following functionality:

  1. figure out username
    • if apache have already logged in the user, use the username
    • if a client certificate is used in the request use the DN as a username
    • if none of the above, then redirect so apache does the authentication
  2. figure out the role
    • make a database lookup based on the username

I have figured out that I might have to write a Filter, and it seems from jk's proxy documentation that I can get the cert and username from the request. I have written the following code:

package com.kodekonveyor.realm;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class KKAuthorizationFilter implements Filter {

private ServletContext context;

@Override
public void init(FilterConfig fConfig) throws ServletException {
    this.context = fConfig.getServletContext();
    this.context.log("KKAuthorizationFilter initialized");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    String user = httpRequest.getRemoteUser();
    Object cert = httpRequest.getAttribute("javax.servlet.request.X509Certificate");
    this.context.log("user:"+user);
    this.context.log("cert:"+cert);
    chain.doFilter(request, response);

}

}

However when I try to reach a servlet with a user which is currently authenticated, or with client ssl authentication, both the user and cert is logged as null. I suspect I have to do some more apache configuration to make it work. A test servlet is at /servlet/servlet in tomcat.

I have the following apache configuration (parts are omitted for brewity)

DocumentRoot /var/www/repo

#correct OIDC configuration omitted

<VirtualHost myhost.mydomain.com:443>
    ServerName myhost.mydomain.com

DBDriver pgsql
#other DBD configurations are omitted

JkMount /servlet* worker1

<Directory /var/www/repo/servlet>
    DirectoryIndex off
    RewriteEngine Off
    AuthType openid-connect
    AllowOverride None
    AuthzDBDQuery "a correct database query"
    Require dbd-group allrepo
LogLevel debug
</Directory>

<Directory /var/www/repo>
    DirectoryIndex off
    RewriteEngine Off
    AllowOverride None
</Directory>

#correct letsencrypt configuration omitted
</VirtualHost>

Solution

  • The cause is found to be the fact that if you have a JkMount in a Location (or perhaps also a Directory) directive, all other autorization and authorization (or even all other?) directives are ineffective.

    An example working configuration for the servlet located at /servlet:

    <Location "/servlet*">
            JkMount  worker1
    </Location>
    <LocationMatch /servlet.*>
        DirectoryIndex off
        RewriteEngine Off
        AuthType openid-connect
        AllowOverride None
        LogLevel debug
        Require valid-user
            SSLOptions +StdEnvVars
            SSLOptions +ExportCertData
            SSLVerifyClient require
    </LocationMatch>
    

    another possible solution:

    <LocationMatch /servlet.*>
           SetHandler jakarta-servlet
           SetEnv JK_WORKER_NAME worker1
           DirectoryIndex off
           RewriteEngine Off
           AuthType openid-connect
           AllowOverride None
           Require valid-user
           LogLevel debug
            SSLOptions +StdEnvVars
            SSLOptions +ExportCertData
            SSLVerifyClient require
    </LocationMatch>
    

    See https://tomcat.markmail.org/thread/iax6picwsjlhbohd for discussion