使用 mod_jk 将用户名和客户端证书从 apache 传递到 tomcat
Pass username and client certificate from apache to tomcat using mod_jk
我想通过 ssl 证书(针对自动化)或 openid(针对人,我使用 auth0 作为提供者)来验证 Web 服务。 tomcat 容器中的 Web 服务 运行,它位于 apache 网络服务器之后,使用 jk。 Web 服务器已经使用 auth0(使用 mod_auth_openidc)对其他路径的用户进行身份验证,并且只能通过 https 访问。我还有一个数据库,当前将 auth0 提供的用户名映射到角色(用于 apache 中的授权)。
我想要以下功能:
- 找出用户名
- 如果apache已经登录用户,使用用户名
- 如果请求中使用了客户端证书,请使用 DN 作为用户名
- 如果 none 以上,则重定向以便 apache 进行身份验证
- 搞清楚角色
- 根据用户名进行数据库查找
我发现我可能必须编写一个过滤器,并且从 jk's proxy documentation 看来我可以从请求中获取证书和用户名。我写了下面的代码:
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);
}
}
但是,当我尝试访问当前已通过身份验证的用户或使用客户端 ssl 身份验证的 servlet 时,用户和证书都记录为空。我怀疑我必须做一些更多的 apache 配置才能使其工作。
测试 servlet 位于 tomcat.
中的 /servlet/servlet
我有下面的apache配置(部分省略了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>
发现原因是,如果您在位置(或目录)指令中有 JkMount,则所有其他授权和授权(甚至所有其他?)指令都无效。
位于 /servlet 的 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>
另一个可能的解决方案:
<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>
我想通过 ssl 证书(针对自动化)或 openid(针对人,我使用 auth0 作为提供者)来验证 Web 服务。 tomcat 容器中的 Web 服务 运行,它位于 apache 网络服务器之后,使用 jk。 Web 服务器已经使用 auth0(使用 mod_auth_openidc)对其他路径的用户进行身份验证,并且只能通过 https 访问。我还有一个数据库,当前将 auth0 提供的用户名映射到角色(用于 apache 中的授权)。
我想要以下功能:
- 找出用户名
- 如果apache已经登录用户,使用用户名
- 如果请求中使用了客户端证书,请使用 DN 作为用户名
- 如果 none 以上,则重定向以便 apache 进行身份验证
- 搞清楚角色
- 根据用户名进行数据库查找
我发现我可能必须编写一个过滤器,并且从 jk's proxy documentation 看来我可以从请求中获取证书和用户名。我写了下面的代码:
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);
}
}
但是,当我尝试访问当前已通过身份验证的用户或使用客户端 ssl 身份验证的 servlet 时,用户和证书都记录为空。我怀疑我必须做一些更多的 apache 配置才能使其工作。 测试 servlet 位于 tomcat.
中的 /servlet/servlet我有下面的apache配置(部分省略了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>
发现原因是,如果您在位置(或目录)指令中有 JkMount,则所有其他授权和授权(甚至所有其他?)指令都无效。
位于 /servlet 的 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>
另一个可能的解决方案:
<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>