sourceforge spnego projectを使用して SSO 認証を実装しました。
あらゆる種類のサーブレット認証を実装するのはこれが初めてなので、私が知らない認証またはサーブレットに関する非常に基本的なものが欠けている可能性があります...
SpnegoHttpFilter
フィルター チェーンの一番上にあるライブラリにパッケージ化されている をオーバーライドなしで使用しています。次に、QueryFilter
ログオン名をデータベースの user_id にマップできるように、フィルター チェーンの次に独自のフィルターを含めました。ログオン名 (Windows ドメインの NT ユーザー ID) はgetRemoteUser
、HttpRequest が を通過した後に呼び出しによって返されSpnegoHttpFilter
ます。これはすべて正常に機能しているようです。
私自身のフィルターQueryFilter
は、本来の処理を行っており、ログオン名をデータベースの user_id に正しくマッピングしています。このフィルターには、認証に合格しないリクエストを拒否するロジックもあります。これも正常に機能しています。未承認のリクエストをシミュレートすると、このフィルターはそれを停止し、サーブレットには到達しません。
問題は、my で認証を通過し、サーブレットで完全に正常に実行された場合でも、すべてのリクエストが 401 (HTTP Request Status Unauthorized) として返されることです。QueryFilter
これを使用して、独自のフィルターで応答を明示的に 200 (HTTP Request Status OK) として定義しようとしましmyHttpResponse.setStatus(HttpServletResponse.SC_OK)
たが、何も変わりませんでした。
問題を切り分けるために、HttpSpnegoFilter
を完全に削除し、ハードコードされたログオン名 (NT ユーザー ID) をQueryFilter
. これは正常に機能し、応答は 401 (Unauthorized) ではなくなりました。
つまり、パッケージ化されたHttpSpnegoFilter
ものが何らかの形でリクエストを に変換していることを意味しUnauthorized
ます。と、言っても変わらない形でやっていて、実はOKなんです。
この spnego sourceforge プロジェクトを使用して、応答ヘッダーを 200 (OK) として返すように設定する方法を知っている人はいますか?
Web アプリの完全なフィルター チェーン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>
完全を期すために以下にも含まれています(ただし、クラスを使用せずにハードコードされたNTユーザーIDを渡すだけでQueryFilter
問題なく動作するため、問題には関係ないようです)。最後から 2 番目の行は、応答が役に立たないSpnegoHttpFilter
ように明示的に指示する場所です。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);
}
}