使用sourceforge spnego对活动目录进行SSO身份验证

时间:2012-04-25 15:55:24

标签: java authentication servlets servlet-filters spnego

我已使用sourceforge spnego project实现了SSO身份验证。

这是我第一次实现任何类型的servlet身份验证,所以我可能会遗漏一些非常基本的身份验证或servlet,我只是不知道......

我正在使用我的过滤器链顶部的库附带的SpnegoHttpFilter而没有覆盖,然后我在过滤器链中包含了我自己的过滤器QueryFilter,以便我可以映射数据库user_id的登录名。在HttpRequest通过getRemoteUser之后,SpnegoHttpFilter调用返回登录名(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.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的完整性(尽管它似乎对我的问题没有任何影响,因为当我不使用{{1类,只是传递一个硬编码的NT用户ID)。倒数第二行是我明确告诉响应为SpnegoHttpFilter无效的地方:

OK

}

1 个答案:

答案 0 :(得分:3)

因为我的应用程序完全基于内部网,所以我最终完全放弃了安全协议。

我只是创建了一个包含所有域IP地址的数据库表,以及当前用户ID,登录时间和注销时间的列。

每当用户登录或注销活动目录时,我都会编写一些服务器端代码来更新此表。

现在,因为我们可以很容易地获得远程地址,所以我编写了一个servlet过滤器:

  1. 检查它们是否是用户ID的HttpSession属性
  2. 如果没有,则在数据库中查询用户ID并将其存储在会话属性中
  3. 根据用户ID执行一些自定义身份验证,并拒绝或传递请求
  4. 如果请求通过过滤器,则向我的servlet发送一个包装的HttpRequest,强制getRemoteUser调用以返回我的用户ID会话属性。
  5. 我认为内联网上的用户可以更改其IP地址以复制其他人,但是当我尝试时,我只是遇到错误,存在重复的IP地址,而我无法连接到任何内容内联网。

    更新(3个月后):

    最后我最终选择了waffle。这很容易整合。上面的解决方案由于多种原因而无法使用。