EJB jax-rs资源上的Jersey自定义SecurityContext

时间:2014-10-22 23:36:38

标签: java-ee jax-rs glassfish-4 jersey-2.0

我正在尝试实现自己的ContainerRequestFilter并配置SecurityContext。它在jax-rs资源上运行良好,但EJB jax-rs抛出javax.ejb.AccessLocalException

我发现只有相关的事情是4岁,而且解决方法看起来并不漂亮。 https://java.net/projects/jersey/lists/users/archive/2010-05/message/265

我的自定义SecurityContext:

@Provider
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext filterContext) throws IOException {
        filterContext.setSecurityContext(new Authorizer());
    }

    public class Authorizer implements SecurityContext {

    public Principal getUserPrincipal() {
        return null;
    }

    public boolean isUserInRole(String role) {
        return true;
    }

    public boolean isSecure() {
        return false;
    }

    public String getAuthenticationScheme() {
        return null;
    }
}

经过测试的资源(不使用@Stateless)

@Path("test")
@Stateless
public class TestSecureResource {

    @GET
    @RolesAllowed("admin")
    @Path("admin")
    public Response secureTest() {
        return Response.status(200).entity("admin").build();
    }

}

有人知道如何使这项工作吗?

3 个答案:

答案 0 :(得分:6)

您可以将JAX-RS SecurityContext用作API而非SPI。应用程序开发人员提供SecurityContext实现的情况并不常见。如果你这样做,你必须知道它只有"本地JAX-RS有效性" ,因为它是一个特定于JAX-RS的API。 Servlet / Web容器和EJB容器都不能使用它。他们没有必要,因为Java SE和EE具有更广泛的安全支持。

如果您希望安全检查在Java EE应用程序中起作用(即EJB上的HttpServletRequest.isUserInRole(...)EJBContext.isCallerInRole(...)javax.annotation.security注释),则需要使用Java EE功能保护Servlet层。这意味着在<security-constraint>中使用web.xml。您可以将*用作<role-name>含义&#34;所有经过身份验证的&#34;用户可以调用REST API:

<security-constraint>
    <web-resource-collection>
        <url-pattern>/rest/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>adminRole</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
        <url-pattern>/rest/orders/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name> <!-- all authenticated users -->
    </auth-constraint>
</security-constraint>

如上所示,当您的Java EE应用程序受到保护时,我们可以使用名为RolesAllowedDynamicFeature的Jersey特定功能在JAX-RS中启用javax.annotation.security注释。

注册功能:

@ApplicationPath("/rest")
public class MyApplication extends ResourceConfig {
    public MyApplication() {
        super(AdminResource.class);
        register(RolesAllowedDynamicFeature.class);
    }
}

保护您的资源:

@Path("/admin")
@RolesAllowed("adminRole")
public class AdminResource {
    @GET
    public String get() { return "GET"; }
    ...
}

请参阅Jersey User guide for more details about securing JAX-RS applications

所以你很亲密。您不需要自己实施SecurityContext。如果处理安全的EJB,则不得实现它。最后,您需要将JAX-RS层保护为常见的Web / Servlet应用程序。我确定您已经保护了您的网页/ HTML页面。

答案 1 :(得分:1)

我终于解决了。我无法使用javax.security.RolesAllowed,因为它的处理方式与EJB容器不同。所以我实现了自己的RolesAllowed注释。它的缺点是它不像原始javax.security.RolesAllowed的实现那么先进。例如,它不像here中描述的那样支持实体过滤。 Java EE社区需要在下一个Java EE 8版本中集成安全性,我希望我们能够看到更好的解决方案。

我将工作示例放在github上。

答案 2 :(得分:0)

我有同样的问题理查德,我按照下面的泽西安全指南。 https://jersey.java.net/documentation/latest/security.html#d0e10816

我使用ContainerRequestFilter进行身份验证,这里我设置了SecurityContext的自定义实现,如果身份验证成功,则rolesalloweddynamic功能将使用rolesallowed注释来授权访问特定资源。 这三个组件允许我在应用程序级别进行身份验证和授权,而不是在容器级别进行身份验证和授权 这很好用,直到我的应用程序从servlet转换为EJB / servlet(我将无状态ejb注释添加到jax-rs资源类)。 EJB使用rolesallowed注释来限制在容器级别访问其bean方法,因此它与我的应用程序级别身份验证/授权冲突。

我仍在寻找一个全面的解决方案,即使它禁用了EJB级方法安全性,因此我可以将其留给ContainerRequestFilter进行身份验证,并允许使用rolesalloweddynamicfeature进行授权。这是我关于这个问题的帖子 Client not authorized for this invocation JAX-RS EJB error