Jakarta ee 在不使用部署描述符的情况下动态添加JavaEE安全角色

Jakarta ee 在不使用部署描述符的情况下动态添加JavaEE安全角色,jakarta-ee,glassfish,ejb,glassfish-3,ejb-3.1,Jakarta Ee,Glassfish,Ejb,Glassfish 3,Ejb 3.1,我正在使用GlassFish3.1B06开发一个JavaEE6应用程序。 为了保护我的应用程序,我使用了JDBCRealm和编程安全性。这可以很好地检查用户名和密码。但在声明安全角色时,我遇到了一个问题: 要在JavaEE6中使用安全角色,我必须在EJB部署描述符和特定于Glassfish的部署描述符中声明这些角色,以链接这些角色(如中所述) 只有这样,我才能在EJB中使用方法isCallerInRole(String roleRef)来检查权限 这对于我的应用程序来说是不可取的,因为我希望能够

我正在使用GlassFish3.1B06开发一个JavaEE6应用程序。 为了保护我的应用程序,我使用了JDBCRealm和编程安全性。这可以很好地检查用户名和密码。但在声明安全角色时,我遇到了一个问题:

要在JavaEE6中使用安全角色,我必须在EJB部署描述符和特定于Glassfish的部署描述符中声明这些角色,以链接这些角色(如中所述) 只有这样,我才能在EJB中使用方法isCallerInRole(String roleRef)来检查权限

这对于我的应用程序来说是不可取的,因为我希望能够以动态和编程的方式添加安全角色,而无需编写XML文件(例如,可以在数据库中定义角色名称)

我刚刚调试了GF3源代码,并在com.sun.ejb.containers.EjbContextImpl中看到了IsCallerRole的实现。在那里,容器从EJB描述符中获取角色:

public boolean isCallerInRole(String roleRef) {
  (...)
  EjbDescriptor ejbd = container.getEjbDescriptor();
  RoleReference rr = ejbd.getRoleReferenceByName(roleRef);
  (...)
}
我环顾四周,发现如果我能以某种方式在我的应用程序中获得EJB描述符,我可以添加如下角色:

EjbDescriptor ejbd = //??? Can i use that descriptor inside my app, or is that "forbidden"?
RoleReference rr = new RoleReference("admin", "Admins are allowed to do everything");
ejbd.addRoleReference(rr);
有人做过这样的事,或者有什么想法吗?可以在我的应用程序中使用Ejb部署描述符吗?还是有更好的方法


还是应该使用MBean来添加角色?找到了一篇非常相关的帖子。

Javadoc确实明确提到了这一要求:

   /**
    * Tests if the caller has a given role.
    *
    * @param roleName - The name of the security role. The role must be one of the security roles that
    * is defined in the deployment descriptor.
    * @return True if the caller has the specified role.
    */
   public boolean isCallerInRole(String roleName);
然而,我发现至少在JBoss中是这样的,因为根本不需要提前声明这些角色。在我们的例子中,主体角色是在系统中动态创建的,并在进行身份验证时进行分配。因此,不可能预先申报这些信息

然而,isCalerInRole方法工作得非常好


我意识到切换到JBoss并不是一个解决方案,但也许这些信息对某些人来说是有价值的。

我提出了以下解决方案,在登录后以编程方式添加角色,这至少在GlassFish 3.1.2 build 23上有效

import com.sun.enterprise.security.SecurityContext;
import com.sun.enterprise.security.web.integration.PrincipalGroupFactory;
import java.security.Principal;
import java.util.Set;
import javax.security.auth.Subject;
import org.glassfish.security.common.Group;

public class GlassFishUtils {
    public static void addGroupToCurrentUser(String groupName, String realmName) {
        Subject subject = SecurityContext.getCurrent().getSubject();
        Set<Principal> principals = subject.getPrincipals();
        Group group = PrincipalGroupFactory.getGroupInstance(groupName, realmName);
        if (!principals.contains(group))
            principals.add(group);
    }
}
导入com.sun.enterprise.security.SecurityContext;
导入com.sun.enterprise.security.web.integration.PrincipalGroupFactory;
导入java.security.Principal;
导入java.util.Set;
导入javax.security.auth.Subject;
导入org.glassfish.security.common.Group;
公共类玻璃鱼{
公共静态void addGroupToCurrentUser(字符串groupName,字符串realmName){
Subject Subject=SecurityContext.getCurrent().getSubject();
Set principals=subject.getPrincipals();
Group Group=PrincipalGroupFactory.getGroupInstance(groupName,realmName);
如果(!principals.contains(组))
添加(组);
}
}
您需要将GlassFish中的
security.jar
common util.jar
添加到项目库中

不要忘了在web.xml中为要添加的角色创建一个
部分

请注意,我使用的功能似乎不是已发布的稳定API的一部分,因此不能保证这将在GlassFish的未来版本中继续工作

我从GlassFish的
sun.appserv.security.AppservPasswordLoginModule.commit()
的源代码中获得了有关如何添加角色的信息。
如果未来的GlassFish发行版破坏了我的代码,那么这个函数将是一个很好的起点,以了解如何修复它。

作为旁白,我鼓励您升级到GlassFish Server 3.1的最新版本。该团队最近发布了build 22.0,谢谢。不幸的是,我们有一些库在更高的Glassfish版本中出现问题,所以我们必须坚持06,直到这些库中的几个bug得到修复。这是解决问题的一个很好的方法。但是,我仍然必须在web.xml中静态地定义角色。但是我想动态添加角色,而不必重新启动服务器。我们最终用了不同的方法。我记不清细节了,但我认为我们用自己的安全机制取代了Glassfish安全机制的很大一部分。我同意ifischer的观点。唯一真正的解决方案是不必静态添加任何内容。这应该添加到规范中。强制声明一度似乎是个好主意,但实际上它受到了严重限制,尤其是在Glassfish中,更是如此冗长。