如何在 JASPIC 中保存经过身份验证的用户?

How to save an authenticated user in JASPIC?

我开发了安全认证模块 (SAM) 并实现了 validateRequest 方法。我还有一个配置为使用此 SAM 的简单网络应用程序。

在我的 validateRequest 方法中,我检查了 clientSubject 并设置了一个带有硬编码用户名的 CallerPrincipalCallback 和一个带有硬编码组名的 GroupPrincipalCallback

final CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject, "anonymous");
final GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject, new String[] {"user"});

try {
  this.handler.handle(new Callback[] {callerPrincipalCallback, groupPrincipalCallback});
} catch (IOException | UnsupportedCallbackException e) {
  logger.error(e.getMessage());
}

我注意到每次我在我的 webapp 中刷新一个 servlet 时,客户端主题都是空白的,logger.debug("Client: {}", clientSubject);:

2015-05-05 11:21:02,200 DEBUG n.m.j.s.Saml2AuthModule [http-listener-1(2)] Client: Subject:

是否可以通过某种方式 "save" 一个主题,以便该主题附加到会话,我可以简单地跳过每次登录同一用户?

编辑 我想我通过手动将其存储在 HttpSession 中找到了一种方法:req.getSession().setAttribute("subject", user); 不漂亮,但它有效。

Is it possible to "save" a subject somehow so that the subject is attached to the session and I can simply skip logging in the same user every time?

是的,虽然 JASPIC 被设计为无状态的,但它确实有一个选项可以半自动记住登录信息。

然而,与仅在会话中存储详细信息并在每个请求开始时重新验证相比,此选项实际上并没有减少多少代码。

方法是先在消息信息映射中设置一个布尔值,然后返回 SUCCESS 并退出 validateRequest:

messageInfo.getMap().put("javax.servlet.http.registerSession", TRUE.toString());

然后在每个请求开始时,您的身份验证模块 (SAM) 仍会被调用,但您可以执行以下 "protocol" 以重新使用存储的身份数据(用户名 + 角色):

HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage();
Principal userPrincipal = request.getUserPrincipal();

if (userPrincipal != null) {   
    handler.handle(new Callback[] { 
        new CallerPrincipalCallback(clientSubject, userPrincipal) }
    );

    return SUCCESS;   
}

我写了一个blog entry with some more details. You can find a test that uses a fully working example in the Java EE 7 samples project.

不幸的是,只要 (http) 会话有效,JASPIC 中没有任何功能表明您根本不想调用 SAM。

如果您喜欢此功能,请为以下问题投票:https://java.net/jira/browse/JASPIC_SPEC-20

I think I found a way by manually storing it in the HttpSession: req.getSession().setAttribute("subject", user); Not pretty, but it works.

或多或少 "official" 方法是将用户名和角色存储在会话中,然后在每次调用 validateRequest 的开始时检查此数据是否存在,如果存在则将其传递转到两个回调。

我上面展示的方法并没有什么不同,但除了明显的区别(一个回调与两个,从请求中获取主体与从会话中获取主体)之外,主要区别在于通过半容器可以自由使用任何它必须存储数据的机制的自动方式。

这可能只是会话中的一个属性(一个简单的 JASPIC 实现肯定可以做到这一点),或者它可以使用大多数容器具有的会话的一些隐藏部分。用户代码不能直接访问这个隐藏部分,这可能有一些优势。