我正在研究jaas,我正在使用带有jaasrealm的tomcat在WebApp中使用一个简单的示例。
现在我的问题是我不知道如何检索主题,因为像 Subject subject = Subject.getSubject(AccessController.getContext());
这样的代码总是返回null。
我正在使用tomcat 7.0.27。有我想念的东西吗?换句话说,如何使用JAAS在Java EE中管理授权?例如,我如何在JAAS的安全上下文中实施一个操作?
我知道这很有效,但是我需要检索主题才能获得roleprincipal
不幸的是,它在Java EE中无法正常工作。JAAS主题只是"校长袋",其中哪个代表用户/呼叫者校长和/或角色主体的角色根本不标准化。其他所有容器在这里做的事情都不同。Tomcat Jaasrealm的Javadoc描述了这一点,并解释了Tomcat的特定惯例(强调我的惯例):
JAAS规范将成功登录的结果描述为 javax.security.auth.subject实例,可以包含零或更多 java.security.principal对象的返回值 bucess.getPrincipals()方法。但是,它不提供指导 如何区分描述个别用户的校长(和 因此适合返回作为价值 Web应用程序中的request.getuserprincipal() 描述了该用户的授权角色。保持尽可能多 尽可能从基础登录 JAAS执行的实施,实施以下策略 通过这个领域:[...]
除此之外,从Java EE环境中,您甚至很少可以访问JAAS主题,甚至通常无法通过供应商特定的方法。JAAS远非您似乎认为是的通用标准,尤其是当它涉及Java EE时。
您唯一可以以便携式方式访问的东西是呼叫者主体及其关联的角色,但即使这些角色也不必是构建的JAAS登录模块的确切呼叫者主体。
jboss,例如,使用自己的类别复制了几次本金。因此,如果您的JAAS模块将kaz.zak.FooPrincipal
存储在用户/呼叫者主体的主题中,则HttpServletRequest#getUserPrincipal()
可能会返回org.jboss.security.SimplePrincipal
。唯一保证的是该实例上的getName()
将返回同一字符串。
有关此主题的更多背景:
- 使用JASPIC在Java EE中实现容器身份验证
- Jaas发生了什么事?
- 将JAAS与Tomcat一起使用
最后一个来源基本上在不同的措辞中说了同一件事;
尽管可以在tomcat中使用JAAS作为身份验证 机构(Jaasrealm),JAAS框架的灵活性丢失了 一旦对用户进行身份验证。这是因为校长是 用来表示"用户"one_answers"角色"的概念,不再是 在执行WebApp的安全环境中可用。这 身份验证的结果仅通过 request.getRemoteuser()和request.isuserinrole()。
这将用于授权目的的JAAS框架减少到一个简单 失去与Java安全性连接的用户/角色系统 政策。
要检索主题,我们可以使用登录模块和阀的组合。在身份验证启动之前调用阀门的事实正在帮助我们在这里。调用阀门时,将会将会话放入threadLocal(类似于JBOSS在threadlocal中保存请求的方式),然后在调用looginmodule.commit()时,将主题保存到会话中。
要配置此添加以下类的添加编译的代码,并将其放在$ catalina_base/lib/plaber下
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/conf/conf/conf/server.xml添加以下阀门配置为元素的孩子。
<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 );