2012-04-25 141 views
1

我已經使用sourceforge spnego project實施了SSO身份驗證。使用sourceforge spnego對照活動目錄進行SSO身份驗證

這是我第一次實施任何形式的servlet身份驗證的,所以我可能會丟失一些非常基本的身份驗證或者說,我只是不知道關於servlet ...

我使用自帶打包SpnegoHttpFilter將過濾器鏈頂部的庫設置爲不覆蓋,然後在過濾器鏈中將我自己的過濾器QueryFilter包括在內,以便我可以將登錄名映射到數據庫user_id。在HttpRequest通過SpnegoHttpFilter之後,登錄名稱(Windows域上的NT用戶ID)由getRemoteUser調用返回,這似乎都工作正常。

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

麻煩的是,所有請求返回爲401(HTTP請求狀態未授權),即使它們通過認證,在我QueryFilter並執行該servlet完全罰款。

我嘗試在我自己的過濾器中使用下面的代碼明確地定義響應爲200(HTTP請求狀態正常):但是這並沒有改變任何東西。

要隔離該問題,我完全刪除了HttpSpnegoFilter,並將一個硬編碼的登錄名(NT用戶標識)傳遞到我的QueryFilter。這工作正常,答覆不再401(未經授權)。

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

有誰知道我可以如何設置響應頭以200(確定)返回使用這個spnego sourceforge項目?

從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> 

我也包括我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); 
} 

}

回答

3

因爲我的應用程序是完全基於內聯網我最後乾脆丟棄的安全協議。

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

無論何時用戶登錄或註銷活動目錄,我都編寫了一些服務器端代碼來更新此表。現在

,因爲我們可以得到遠程地址很容易的,我寫了一個Servlet過濾器是:

  1. 檢查,如果他們是用戶ID
  2. 如果沒有一個HttpSession屬性,查詢數據庫在一個會話屬性
  3. 的用戶ID,並存儲基於所述用戶ID一些自定義身份驗證,並且如果該請求通過過濾器發送我的servlet包裹的HttpRequest使得力getRemoteUser呼叫噸拒絕或將請求傳遞
  4. o返回我的用戶ID會話屬性。

我想這將有可能爲用戶在Intranet上改變自己的IP地址,複製別人,但是當我試圖我剛剛得到一個重複的IP地址存在錯誤,我無法連接到內聯網上的任何東西。

更新(3個月以後):

我結束了在年底與waffle去。整合非常簡單。上述解決方案由於多種原因無法使用。