EJB安全问题:角色和身份验证方面的疑问

9

如果有人能帮助我回答以下问题,我将非常感激:

  1. @RolesAllowed和@DeclareRoles注释之间有什么区别?
  2. 我开发了一个登录功能,可以检查用户名和密码是否与数据库中的信息匹配。但是我想知道如何为经过身份验证的用户分配角色,以便与上述注释一起使用。
2个回答

21
@RolesAllowed和@DeclareRoles注解之间有什么区别?
@RolesAllowed注解用于指定实际允许访问业务方法的角色列表。 EJB容器在运行时的行为受到此注解的影响,因为EJB容器会主动验证调用者是否在允许的角色中。同时,此注解可以定义在TYPE和METHOD上,允许您在类或方法级别上定义允许的角色列表。您可以在单个方法的级别上覆盖所有方法的允许角色列表。
另一方面,@DeclareRoles注解仅用于声明角色列表; 它相当于ejb-jar.xml文件中security-role-ref元素的等效物。EJB容器不需要知道这些角色来强制执行EJB的业务方法的访问控制检查; 相反,bean提供程序/开发人员可以在isCallerInRole测试中使用这些角色来确保编程安全。
EJB 3.1规范对@DeclareRoles注解的说明如下:
17.2.5.3 Declaration of Security Roles Referenced from the Bean’s Code Bean提供者负责使用DeclareRoles注解或部署描述符中的security-role-ref元素声明企业bean代码中使用的所有安全角色名称。DeclareRoles注解在bean类上指定,其中它用于声明可以通过在注释类的方法内调用isCallerInRole来测试的角色。声明安全角色允许Bean提供者,应用程序组装器或部署器将在代码中使用的这些安全角色名称链接到为组装应用程序定义的安全角色。如果没有此链接步骤,则假定在代码中使用的任何安全角色名称都对应于相同名称的安全角色。

您的问题的第二部分如下:

我已经开发了一个登录功能,用于检查用户名和密码是否与数据库中的信息匹配。但是,我想问一下如何为经过身份验证的用户分配角色以供上述注释使用。

在这种情况下,需要注意的一般点是,除非您的用例确实需要它,否则我的首选方法是不使用编程安全性。在大多数情况下,如果可以通过声明性安全实现要求,则最好使用它,因为编程安全性要求您跟踪isCallerInRole方法调用,并且没有这样的调用可能导致安全漏洞。无论哪种方式,在您的情况下,您需要使容器首先识别数据库中的组和主体作为可用于访问控制检查的角色。

简而言之,EJB客户端(Java SE应用程序、Servlet或另一个EJB)必须首先对容器的安全机制进行身份验证,以建立调用者的Principal。因此,成功使用声明性或编程安全性取决于成功的身份验证过程。在您的情况下,您需要配置容器以识别数据库中的组和用户,并将其转换为可以用于以声明性或编程方式强制执行访问控制的Principal对象。大多数容器支持一种或多种JAAS登录模块,用于此目的;例如,Glassfish 3.1可以使用JDBCRealm实现此目的,而JBoss 6.0则支持DatabaseServerLoginModule。因此,您需要确定您的容器是否支持此类登录模块,并将其配置为使用您的数据库。

请注意,在某些情况下,容器提供的登录模块可能无法满足您的需求。这种情况下,您需要编写自己的登录模块(如果需要,可以针对容器的接口进行编写)。

另外,您还需要将应用程序使用的角色映射到 JAAS 领域中的用户和组。例如,如果您的数据库是由 JAAS 领域使用:

  • 包含用户 U1U2U3U4U5,以及
  • 包含组 G1G2G3,分别包含 U1U2U3
  • 并且您的 EJB 允许使用通过 @RolesAllowed 注解定义的角色 R1R2R3 的用户访问其方法,

那么您需要将角色映射到 JAAS 领域中的主体(用户和组)。即使角色名称与主体名称相同,也必须进行映射;Glassfish 通过支持默认主体到角色映射来简化此过程,直接将具有类似名称的主体(用户或组)映射到角色。此外,映射的过程是容器特定的,并且正如您所想象的那样,此映射是在容器特定的部署描述符中执行而不是在 EJB 部署描述符(ejb-jar.xml)中执行。

为了完成答案,您需要为每个创建的用户分配一个角色。为了简单起见,您可以创建一个单独的用户组,所有用户都可以属于该组。当用户对JAAS领域进行身份验证时,Principal对象将包含此组。您的JAAS领域中的组然后可以映射到EJB角色,并且角色名称可以在@RolesAllowed注释中指定。任何不属于此组的数据库中的用户都将被EJB容器阻止访问已注释的方法。

这是一个非常好而且详尽的回答。有一个补充;在 Java EE 6+ 中,不再严格需要“[code]针对容器接口”。现在通过 JASPIC SPI 有Java EE标准化接口可用。 - Arjan Tijms

2
也许我的答案可能不正确,也可能不完整。但是可以在这个参考链接中找到: http://openejb.apache.org/3.0/security-annotations.html DeclareRoles 只能用在类级别上。 当通过isCallerInRole(roleName)引用角色时,需要更新@DeclareRoles。
基本思路:
默认情况下,业务接口的所有方法都是可访问的,无论是否登录。 注释应该放在bean类上,而不是业务接口上。 安全注释可以应用于整个类和/或单个方法。 使用的任何安全角色名称必须通过@DeclareRoles声明。 @RolesAllowed 可用于类级别和方法级别以限制访问级别。
一个例子: 混合类和方法级别限制 安全注释可以同时用于类级别和方法级别。这些规则不会叠加,因此标记“submitPatch”会覆盖默认值“committers”。
@Stateless
@DeclareRoles({"committer", "contributor"})
@RolesAllowed({"committer"})
public class OpenSourceProjectBean implements Project {

    public String svnCommit(String s) {
        return s;
    }

    public String svnCheckout(String s) {
        return s;
    }

    @RolesAllowed({"contributor"})
    public String submitPatch(String s) {
        return s;
    }
}

编辑:

这里是SQLLoginModule的代码片段。您可以使用此模块作为登录模块。通过这种方式,您可以遵循JAAS标准。

在提交中,它将调用此函数以添加主体。

subject.getPrincipals().addAll(allPrincipals);

此外,您可以在此处查看更多详细信息http://openejb.apache.org/3.0/security.html

该网页列出了其他可供选择的选项。


谢谢你的回答。你有什么想法可以解决我的第二个问题吗?=) - Mr.J4mes
嗯...我有另一个小问题。在用户通过Web Servlet登录后,是否可以在他的会话Cookie中记录此用户的角色?这会类似于“session.setAttribute(“ role”,somethinghere)”吗?我的意思是如何记录他的角色,以便他能够访问方法而无需反复登录。 - Mr.J4mes
你可以这样做,但这是另一个问题。你可以选择将它保存在cookie或session中。 - Clark Bao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接