簡體   English   中英

使用sourceforge spnego對活動目錄進行SSO身份驗證

[英]SSO authentication against active directory using sourceforge spnego

我使用sourceforge spnego項目實現了SSO身份驗證。

這是我第一次實現任何類型的servlet身份驗證,所以我可能會遺漏一些非常基本的身份驗證或servlet,我只是不知道...

我正在使用與我的過濾器鏈頂部的庫一起打包的SpnegoHttpFilter而沒有覆蓋,然后我在過濾器鏈中接下來包含了我自己的過濾器QueryFilter ,以便我可以將登錄名映射到數據庫user_id。 在HttpRequest通過SpnegoHttpFilter之后, getRemoteUser調用返回登錄名(Windows域上的NT用戶ID),這一切似乎都正常。

我自己的過濾器QueryFilter正在做它應該做的事情,它正確地將登錄名映射到數據庫user_id。 我在此過濾器中也有邏輯來拒絕未通過我的身份驗證的請求,這也正常工作:當我模擬未經授權的請求時,此過濾器會停止它並且它永遠不會進入servlet。

問題是所有請求都返回401(HTTP請求狀態未授權),即使它們在我的QueryFilter通過身份驗證並在servlet上執行完全正常。

我嘗試使用以下方法在我自己的過濾器中明確地將響應定義為200(HTTP請求狀態正常): myHttpResponse.setStatus(HttpServletResponse.SC_OK)但這並未改變任何內容。

為了隔離這個問題,我完全刪除了HttpSpnegoFilter ,只是將一個硬編碼的登錄名(NT用戶ID)傳遞給了我的QueryFilter 這很好,響應不再是401(未經授權)。

這意味着打包的HttpSpnegoFilter以某種方式將請求轉換為Unauthorized 並且當我說它實際上沒問題時,它會以一種不會改變的方式進行。

有誰知道如何使用這個spnego sourceforge項目將響應頭設置為200(OK)?

我在web-app的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);
}

}

因為我的應用程序完全基於內部網,所以我最終完全放棄了安全協議。

我只是創建了一個數據庫表,其中包含我的所有域IP地址以及當前用戶ID,登錄時間和注銷時間的列。

每當用戶登錄或注銷活動目錄時,我都會編寫一些服務器端代碼來更新此表。

現在,因為我們可以很容易地得到遠程地址,所以我編寫了一個servlet過濾器:

  1. 檢查它們是否是用戶標識的HttpSession屬性
  2. 如果不是,則在數據庫中查詢用戶ID並將其存儲在會話屬性中
  3. 根據用戶ID執行一些自定義身份驗證,並拒絕或傳遞請求
  4. 如果請求傳遞過濾器,則向我的servlet發送一個包裝的HttpRequest,強制getRemoteUser調用返回我的用戶ID會話屬性。

我想Intranet上的用戶可能會更改他們的IP地址以復制其他人,但是當我嘗試時,我發現錯誤的是存在重復的IP地址,而我無法連接到Intranet上的任何內容。

更新(3個月后):

最后我最后還是用華夫餅干 這很容易整合。 由於多種原因,我上面的解決方案無法實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM