无需使用部署描述符即可动态添加Java EE安全角色

时间:2010-09-30 09:10:11

标签: java-ee glassfish ejb glassfish-3 ejb-3.1

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

要在Java EE 6中使用安全角色,我必须在EJB部署描述符和Glassfish特定部署描述符中声明这些角色以链接这些角色(如Java EE 6-tutorial中所述) 只有我可以使用EJB中的方法 isCallerInRole(String roleRef)来检查权限。

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

我刚刚通过GF3源代码进行了调试,并在 com.sun.ejb.containers.EjbContextImpl 中看到了isCallerInRole的实现。容器从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部署描述符?或者有更好的方法吗?

P.S。或者我应该使用MBeans添加角色?找到一篇相关的帖子here

2 个答案:

答案 0 :(得分:3)

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 AS中,根本不需要提前声明这些角色。在我们的示例中,主要角色是在系统中动态创建的,并在进行身份验证时分配。因此不可能事先声明这些。

然而,isCallerInRole方法非常有效。

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

答案 1 :(得分:3)

我想出了以下解决方案,在登录后以编程方式添加角色,至少在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);
    }
}

您需要将GlassFish中的security.jarcommon-util.jar添加到项目库中。

不要忘记在web.xml中为要添加的角色创建一个<security-role>部分。

请注意,我使用的功能似乎不是已发布的稳定API的一部分,因此无法保证这将在以后的GlassFish版本中继续有效。

我从GlassFish的sun.appserv.security.AppservPasswordLoginModule.commit()源代码中获取了有关如何添加角色的信息。 如果未来的GlassFish版本破坏了我的代码,那么这个函数将是一个很好的起点,以便找到解决方法。