Tomcat-Jaas - 如何检索主题?

时间:2012-10-25 10:20:10

标签: java-ee tomcat jaas jaspic

我正在学习JAAS,而我正在使用Tomcat和JaasRealm实现一个在webapp中使用的简单示例。

现在我的问题是我不知道如何检索主题,因为像Subject subject = Subject.getSubject(AccessController.getContext());这样的代码总是返回null。

我正在使用Tomcat 7.0.27。有没有我错过的东西? 换句话说,如何使用JAAS管理Java EE中的授权?例如,如何在JAAS的安全上下文中实现操作?

2 个答案:

答案 0 :(得分:8)

  

我知道并且它有效,但我需要检索主题以获得角色主题

不幸的是,它在Java EE中的工作方式不同。 JAAS主题只是一个“主要包”,其中哪些代表用户/调用者主体和/或角色主体根本不是标准化的。每个其他容器在这里做不同的事情。 Javadoc for Tomcat's JAASRealm描述了这一点并解释了Tomcat特定约定(强调我的):

  

JAAS规范描述了成功登录的结果   javax.security.auth.Subject实例,可以包含零个或多个   java.security.Principal对象中的返回值   Subject.getPrincipals()方法。但是,没有提供任何指导   如何区分描述个人用户的主体(和   因此适合作为价值返回   来自Principal(s)的web应用程序中的request.getUserPrincipal()   描述此用户的授权角色。保持尽可能多   尽可能独立于底层的LoginMethod   由JAAS执行的实现,实现了以下策略   通过这个领域:[...]

除此之外,从Java EE环境中,您甚至很少能够访问JAAS主题,甚至通常也不会通过特定于供应商的方法。 JAAS远不是您认为的通用标准,特别是当它涉及Java EE时。

您可以以可移植方式访问的唯一内容是调用者主体和与之关联的角色,但即使这些内容也不一定是JAAS登录模块构造的确切调用者主体。

例如,JBoss AS使用自己的类复制此主体几次。因此,如果您的JAAS模块将kaz.zak.FooPrincipal存储到用户/调用者主体的主题中,则HttpServletRequest#getUserPrincipal()可能会返回org.jboss.security.SimplePrincipal。唯一保证的是该实例上的getName()将返回相同的字符串。

有关此主题的更多背景信息:

最后一个来源基本上用不同的措辞说同样的事情;

  

尽管可以在Tomcat中使用JAAS作为身份验证   机制(JAASRealm),JAAS框架的灵活性丢失了   一旦用户通过身份验证。这是因为校长是   用来表示“用户”和“角色”的概念,不再是   在执行webapp的安全上下文中可用。该   身份验证的结果只能通过   request.getRemoteUser()和request.isUserInRole()。

     

这将JAAS框架的授权目的简化为简单   用户/角色系统失去与Java安全性的连接   政策。

答案 1 :(得分:0)

要检索主题,我们可以使用LoginModule和Valve的组合。在认证开始之前调用阀门的事实在这里帮助我们。当调用Valve时,它会将会话放入ThreadLocal中(类似于JBOSS在ThreadLocal中保存请求的方式),稍后当调用LoginModule.commit()时,会将主题保存到会话中。

配置此项将以下类的编译代码添加到jar并将其放在$ CATALINA_BASE / lib /

package my.test;

import java.io.IOException;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import javax.servlet.ServletException;

import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

/**
 * Use following class to retrieve subject in your HTTPServlet when using Tomcat.
 */
public class ContainerServices extends ValveBase implements LoginModule {

    // Key to revtieve subject from session.
    public static final String SUBJECT_KEY =
        "javax.security.auth.Subject.container";

    /**
     * Session for current thread.
     */
    static InheritableThreadLocal<Session> sessionHolder =
        new InheritableThreadLocal<Session>();

    // JAAS Subject being authenticated.
    private Subject subject;

    // Invoke the value.
    public void invoke(Request request, Response response) throws IOException,
            ServletException {

        sessionHolder.set(request.getSessionInternal(true));

        try {
            // Next in the invocation chain
            getNext().invoke(request, response);
        } finally {
            sessionHolder.remove();
        }
    }

    // Initialize the login module
    public void initialize(Subject subject, CallbackHandler callbackHandler,
        Map<String, ?> sharedState, Map<String, ?> options) {
        this.subject = subject;
    }

    // Store subject to session.
    public boolean commit() throws LoginException {

        Session session = sessionHolder.get();

        if (session != null) {
            session.getSession().setAttribute(ContainerServices.SUBJECT_KEY, subject);
        }

        return true;
    }

    // not used
    public boolean abort() throws LoginException {
        return false;
    }

    // not used
    public boolean login() throws LoginException {
        return true;
    }

    // not used
    public boolean logout() throws LoginException {
        return true;
    }
}

在$ CATALINA_BASE / conf / server.xml中添加以下Valve配置作为元素的子项。

<Valve className="my.test.ContainerServices" />

在jaas.config文件中添加与LoginModule相同的类。

DummyAppLogin {
    my.test.ContainerServices required debug=true;
    my.test.DummyAppLoginModule required debug=true;
};

现在登录后,可以使用以下内容检索经过身份验证的主题。

session.getAttribute( ContainerServices.SUBJECT_KEY );