javax.ejb.EJBAccessException: 调用者未经授权

javax.ejb.EJBAccessException: Caller unauthorized

在将应用程序从带有 quartz-ra.rar 的 QuartzMDB 迁移到 Jboss AS 6.1 中的 EJB 计时器后,我遇到了上述异常。 (作为将应用程序升级到 Wildfly 8.1 的一部分)

使用以下 ejb 的作业发生异常。

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@RolesAllowed({"admin"})
public class PlatformPluginBean implements PlatformPluginRemote {

    // some code here

    public Collection<PlatformPlugin> getPlugins() {
        return new ArrayList<PlatformPlugin>(schemaToPlugin.values());
    }

}

以下是迁移前的工作,效果很好。

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0 0 * * * ?"),
    @ActivationConfigProperty(propertyName = "jobName", propertyValue = "PruneJob")})
@ResourceAdapter("quartz-ra.rar")
@RunAs("admin")
public class PruneJob implements Job {

    @EJB
    private PlatformPluginRemote platformPluginRemote;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        for (PlatformPlugin platformPlugin: platformPluginRemote.getPlugins()) {
            // some stuff here
        }
    }
}

以下是改成ejb自动定时器后的工作

@Stateless
@RunAs("admin")
public class PruneJob {

    @EJB
    private PlatformPluginRemote platformPluginRemote;

    @Schedule(hour="*", minute="0", persistent=false)
    public void execute() {

        for (PlatformPlugin platformPlugin: platformPluginRemote.getPlugins()) {
            // some stuff here
        }
    }
}

异常发生在 platformPluginRemote.getPlugins() 调用。

JBoss 5 中报告了这个 issue,它也影响 jboss 作为 6.1,要修复它,您可以在文件 JBOSS_HOME/serve/<instance>/deploy/ejb3-interceptors-aop.xml 中添加 org.jboss.ejb3.security.RunAsSecurityInterceptorFactory拦截器:

例如:

<! - The additional MDB specific ones ->
<interceptor-ref name = "org.jboss.ejb3.ENCPropagationInterceptor" />
<interceptor-ref name = "org.jboss.ejb3.security.RunAsSecurityInterceptorFactory" />
<interceptor-ref name = "CMTTx" />
<interceptor-ref name = "org.jboss.ejb3.stateless.StatelessInstanceInterceptor" />
<interceptor-ref name = "org.jboss.ejb3.tx.BMTTxInterceptorFactory" />
<interceptor-ref name = "org.jboss.ejb3.AllowedOperationsInterceptor" />
<interceptor-ref name = "org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor" />

在实践中它给我带来了一些问题,不是所有的调用都会传播角色,有时会发生授权错误。

或者您可以在 MDB 的 execute() 方法中使用 Subject.doAs()。不要忘记在您的安全域中添加登录模块 ClientLoginModule。

@RunAs("admin") 注释由于某种原因似乎不起作用(jboss 错误?)

同样可以通过在调用 ejb 之前添加以下代码来完成。

SecurityContextAssociation.getSecurityContext().setOutgoingRunAs(new RunAsIdentity("admin", "admin"));