如何在 TomEE 中为 EJB 方法配置安全限制?

How to configure security restrictions for EJB methods in TomEE?

基本上,我无法使@RolesAllowed 注释起作用。看来容器完全无视了。

但是,isCallerInRole() 方法可以正常工作。

只有管理员才能调用下面的方法,但每次都会调用该方法,尽管用户只有 "guest" 角色。

@Remote
public interface SomeManager {
    void performImportantTask();
}

@Stateless
@DeclareRoles({"guest", "admin"})
public class SomeManagerBean implements SomeManager {    
    @Resource private EJBContext context;

    @RolesAllowed({"admin"})
    @Override public void performImportantTask() {
        logger.info(context.getCallerPrincipal().getName()); // prints the correct user name

        if (context.isCallerInRole("admin")) {
            logger.info("Is admin"); // doesn't print
        }

        if (context.isCallerInRole("guest")) {
            logger.info("Is guest"); // prints
        }
    }
}

为什么调用这个方法,即使容器清楚地知道用户不是管理员?

我还尝试用@DenyAll 替换@RolesAllowed 并且这没有任何否定 - 该方法仍然执行。

这是server.xml中的realm配置:

...
            <Realm className="org.apache.catalina.realm.LockOutRealm">
                <Realm className="org.apache.catalina.realm.DataSourceRealm"
                       dataSourceName="securityDS"
                       userTable="users"
                       userNameCol="user_name"
                       userCredCol="user_pass"
                       userRoleTable="user_roles"
                       roleNameCol="role_name"/>
            </Realm>
            ...            
        </Engine>
    </Service>
</Server>

很可能是我遇到了一些配置问题,但我不知道该从哪里查找。 还是我理解有误?

我假设 tomcat_users.xml 文件与 DataSourceRealm 无关。 尽管如此,考虑到我可能需要在此文件中定义角色,我还是这样添加了它们:

<tomcat-users ...>
  <role rolename="admin"/>
  <role rolename="guest"/>
</tomcat-users>

但这并没有改变上面的场景。

相关文档:

TomEE Security Annotations

DataSourceRealm and TomEE DataSource

请注意,一个应用服务器可能有多个应用程序和多个领域。每个应用程序都可以配置为使用特定领域并将领域用户和组映射到应用程序中的角色。

在你的例子中:

  • server.xml习惯于define one or more realms in the server
  • tomcat_users.xml 允许您为默认 UserDatabaseRealm 而不是 DataSourceRealm 定义用户。这些领域适用于 Web 应用程序。

How to configure security restrictions for EJB methods in TomEE?

我认为 TomEE 中的 EJB 使用 Java Authentication and Authorization (JAAS)。您必须在 server.xmlcontext.xml 中配置 JAAS 领域,并使用 login.config 文件配置领域。您必须设置 java.security.auth.login.config 系统 属性 以指向该文件:


示例: TomEE rest-jaas example 显示了一个使用 PropertiesLogin 模块的应用程序,即使用文件来存储用户和密码。

  1. 在命令行中,你可以运行像这样:

    set CATALINA_OPTS="Djava.security.auth.login.config=$CATALINA_BASE/conf/login.config"
    

    如果你运行 TomEE 使用maven,你可以在<pluing>里面定义变量<build>pom.xml

    <plugin>
      <groupId>org.apache.tomee.maven</groupId>
      <artifactId>tomee-maven-plugin</artifactId>
      <version>7.0.5-SNAPSHOT</version>
      <configuration>
        <systemVariables>
          <java.security.auth.login.config>${project.build.directory}/apache-tomee/conf/login.config</java.security.auth.login.config>
        </systemVariables>
        <context>ROOT</context>
      </configuration>
    </plugin>
    
  2. login.config 中配置 JAAS 领域。 TomEE 示例通常使用 PropertiesLogin 将用户和密码存储在 .properties 文件中。

    PropertiesLogin {
        org.apache.openejb.core.security.jaas.PropertiesLoginModule required
        Debug=false
        UsersFile="users.properties"
        GroupsFile="groups.properties";
    };
    

    有使用其他登录模块的 OpenEJB 示例,例如 SQLLogin

    SQLLogin {
        org.apache.openejb.core.security.jaas.SQLLoginModule required
        jdbcURL="jdbc:hsqldb:mem:sqltest"
        userSelect="SELECT username, password FROM users WHERE username = ?"
        groupSelect="SELECT username, grp FROM groups WHERE username = ?";
    };
    

    如果您定义多个领域。您可以更改自定义名称的 PropertiesLoginSQLLogin 根名称。

  3. 最后,您必须在server.xml(或context.xml)配置JAAS领域。例如,您可以在 server.xml.

    <Engine> 中包含一个 <Realm>
    <Realm className="org.apache.catalina.realm.JAASRealm" appName="PropertiesLogin"
         userClassNames="org.apache.openejb.core.security.jaas.UserPrincipal"
         roleClassNames="org.apache.openejb.core.security.jaas.GroupPrincipal">
    

    appName 因您在上述 login.config 文件中定义的名称而异。 userClassNamesroleClassNames 因 JAAS 提供程序而异。


其他模块:您可以使用其他兼容 JAAS 的登录模块。有许多包含在标准 java 和 OpenEJB 中。您可以查看:

  • LoginConfig file 的 java 文档,了解有关标准 JndiLoginModuleKeyStoreLoginModuleKrb5LoginModuleNTLoginModule 和 [=46] 的信息=] 模块。
  • OpenEJB 有 other login modules,包括上面提到的两者(PropertiesLoginSQLLogin)。
  • 并且您可以检查 the JAAS documentation 并创建您自己的登录模块。

示例: 有一些 TomEE examples(maven 项目)展示了如何配置和测试使用 JAAS 注释的组件(Java 身份验证和授权),你可以检查:

  • ejb-examples 包括一个安全的 EJB。
  • moviefun 包括 运行 特定用户的单元测试,
  • rest-jaas 向您展示如何保护 REST 端点。