我已经使用sourceforge spnego 项目实现了 SSO 身份验证。
这是我第一次实现任何类型的 servlet 身份验证,所以我可能会遗漏一些非常基本的身份验证或我不知道的 servlet...
我使用的SpnegoHttpFilter
是与我的过滤器链顶部的库一起打包的,没有覆盖,然后我QueryFilter
在过滤器链中包含我自己的过滤器,以便我可以将登录名映射到数据库 user_id。登录名称(Windows 域上的 NT 用户 ID)getRemoteUser
在 HttpRequest 通过后由调用返回SpnegoHttpFilter
,这一切似乎都工作正常。
我自己的过滤器QueryFilter
正在做它应该做的事情,它将登录名正确映射到数据库 user_id。我在此过滤器中也有逻辑来拒绝未通过我的身份验证的请求,这也可以正常工作:当我模拟未经授权的请求时,此过滤器将其停止,并且永远不会到达 servlet。
问题是所有请求都返回 401(未经授权的 HTTP 请求状态),即使它们通过了 my 中的身份验证QueryFilter
并在 servlet 上完全正常执行。
我尝试使用以下方法在我自己的过滤器中将响应明确定义为 200 (HTTP Request Status OK):myHttpResponse.setStatus(HttpServletResponse.SC_OK)
但这并没有改变任何东西。
为了隔离问题,我HttpSpnegoFilter
完全删除了这个问题,只是将一个硬编码的登录名(NT 用户 ID)传递给我的QueryFilter
. 这工作正常,响应不再是 401(未经授权)。
这意味着打包HttpSpnegoFilter
以某种方式将请求转换为Unauthorized
. 当我说它实际上没问题时,它不会改变。
有谁知道如何使用这个 spnego sourceforge 项目将响应标头设置为返回 200(OK)?
我来自网络应用程序的完整过滤器链web.xml
如下,如前所述,我使用HttpSpnegoFilter
链顶部的包装,然后在其下方使用我自己的过滤器(这似乎正确地完成了它的工作):
<filter>
<filter-name>SpnegoHttpFilter</filter-name>
<filter-class>net.sourceforge.spnego.SpnegoHttpFilter</filter-class>
<init-param>
<param-name>spnego.allow.basic</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>spnego.allow.delegation</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>spnego.allow.localhost</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>spnego.allow.unsecure.basic</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>spnego.login.client.module</param-name>
<param-value>spnego-client</param-value>
</init-param>
<init-param>
<param-name>spnego.krb5.conf</param-name>
<param-value>krb5.conf</param-value>
</init-param>
<init-param>
<param-name>spnego.login.conf</param-name>
<param-value>login.conf</param-value>
</init-param>
<init-param>
<param-name>spnego.preauth.username</param-name>
<param-value>myADServicePrincipal</param-value>
</init-param>
<init-param>
<param-name>spnego.preauth.password</param-name>
<param-value>myADServicePrincipalPassword</param-value>
</init-param>
<init-param>
<param-name>spnego.login.server.module</param-name>
<param-value>spnego-server</param-value>
</init-param>
<init-param>
<param-name>spnego.prompt.ntlm</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>spnego.logger.level</param-name>
<param-value>1</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SpnegoHttpFilter</filter-name>
<servlet-name>QueryServlet</servlet-name>
</filter-mapping>
<filter>
<filter-name>QueryFilter</filter-name>
<filter-class>my.package.name.QueryFilter</filter-class>
<init-param>
<param-name>query.permission.list</param-name>
<param-value>getQueryPermission</param-value>
</init-param>
<init-param>
<param-name>remote.user.column</param-name>
<param-value>nt_user_id</param-value>
</init-param>
<init-param>
<param-name>user.id.column</param-name>
<param-value>user_id</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>QueryFilter</filter-name>
<servlet-name>QueryServlet</servlet-name>
</filter-mapping>
我还在QueryFilter
下面包含了我的完整性(尽管它似乎与我的问题没有任何关系,因为当我不使用SpnegoHttpFilter
该类并仅将硬编码的 NT 用户 ID 传递给它时,它本身就可以正常工作)。倒数第二行是我明确告诉响应OK
无效的地方:
import java.io.IOException;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public final class QueryFilter implements Filter {
private MapListDAO myMapListDAO;
private String myPermissionsList;
private String myRemoteUserColumn;
private String myUserIdColumn;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
myMapListDAO = Config.getInstance(filterConfig.getServletContext()).getMapListDAO();
myPermissionsList = filterConfig.getInitParameter("query.permission.list");
myRemoteUserColumn = filterConfig.getInitParameter("remote.user.column");
myUserIdColumn = filterConfig.getInitParameter("user.id.column");
}
@Override
public void destroy() {
// TODO ...?
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String queryName = request.getParameter("queryName");
// because I have SpnegoHttpFilter earlier in my filter chain
// this returns the NT User ID (what the user logged in to the domain with)
String remoteUser = httpRequest.getRemoteUser();
Map<String, Object> queryPermissions = myMapListDAO.getEntry(myPermissionsList, myRemoteUserColumn, remoteUser);
// if there is no queryName defined
if (null == queryName) {
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Missing queryName parameter.");
return;
}
// if this query is protected perform the gauntlet
if (myMapListDAO.getList(myPermissionsList).get(0).containsKey(queryName)) {
// if there is no remoteUser
if (null == remoteUser || remoteUser.isEmpty()) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Cannot get remoteUser.");
return;
}
// if the remoteUser does not have any queryPermissions
if (null == queryPermissions) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Cannot find queryPermissions for " + remoteUser + ".");
return;
}
// if this remoteUser does not have permission to execute the queryName
if ((Boolean) queryPermissions.get(queryName)) {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"The remoteUser: " + remoteUser + " does not have permission to access queryName: " + queryName + ".");
return;
}
}
// attempt to add the userId to this request as an attribute we can get later
if (null != queryPermissions) {
httpRequest.setAttribute("userId", String.valueOf(queryPermissions.get(myUserIdColumn)));
}
// continue to servlet
httpResponse.setStatus(HttpServletResponse.SC_OK);
chain.doFilter(request, response);
}
}
// attempt to add the userId to this request as an attribute we can get later
if (null != queryPermissions) {
httpRequest.setAttribute("userId", String.valueOf(queryPermissions.get(myUserIdColumn)));
}
// continue to servlet
httpResponse.setStatus(HttpServletResponse.SC_OK);
chain.doFilter(request, response);
}
}