使用注释使用基本身份验证保护Glassfish REST服务

时间:2012-11-29 17:00:35

标签: rest annotations glassfish glassfish-3 basic-authentication

我一直在尝试保护一个应用程序,该应用程序使用注释而不是部署描述符部署到glassfish 3。但是,我无法让它正常工作。如果我尝试访问该服务,我最终会收到服务器错误500,显示以下消息:

type Exception report

message

descriptionThe server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: javax.ejb.AccessLocalException: Client not authorized for this invocation
root cause

javax.ejb.AccessLocalException: Client not authorized for this invocation

EJB看起来像这样:

@Path("/myresource")
@Stateless
@RolesAllowed("user-role")
public class MyResource {

    @GET
    @Path("/{uuid}")
    public Response getData(@PathParam("uuid") final String uuid) {
            ....
    }
}

sun-web.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD GlassFish Application Server 3.0 Servlet 3.0//EN" 
"http://www.sun.com/software/appserver/dtds/sun-web-app_3_0-0.dtd">
<sun-web-app>
    <security-role-mapping>
        <role-name>user-role</role-name>
        <group-name>user-group</group-name>
    </security-role-mapping>
</sun-web-app>

这是web.xml:

<web-app id="myservice" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>org.test.myservice</display-name>

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>org.test.myservice.rest</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>file</realm-name>
    </login-config>

    <security-role>
        <role-name>user-role</role-name>
    </security-role>
</web-app>

glassfish中的文件域是使用sun-web.xml中指定的用户和角色设置的,并且在通过部署描述符设置应用程序安全性时运行良好。

如果我正确理解了这个文档,如果它们的名称相同,我就不必链接安全角色引用。 http://docs.oracle.com/javaee/5/tutorial/doc/bnbyl.html#bnbyt 我缺少什么想法?

修改 与无法使用注释指定所需信息的问题相关,还有另一个问题,这使我想到了这个问题。也许这会使最初的问题更加清晰: 以上为例,资源/ myresource / *仅适用于角色为“user-role”的用户。但是,如果路径/ myresource / * / thumbnail(转换为/ myresource / [uuid] / thumbnail)中有第二个资源(无需身份验证即可使用),则无法通过url-mapping指定security-constraints,因为似乎不可能在常量之间使用通配符。但是,通过指定允许通过注释访问方法的角色,这是可行的。如上所述,我无法这样做。怎么可以做这样的映射?

2 个答案:

答案 0 :(得分:2)

您需要使用web.xml描述符中的security-constraint元素来阻止特定资源和路径,并指定授权约束。

这并不意味着您无法使用Programmatic Security添加更细粒度的控件,如Oracle's Java EE 6 Tutorial中所述:

  

程序化安全性嵌入在应用程序中,用于做出安全决策。当声明性安全性不足以表达应用程序的安全模型时,编程安全性很有用。


根据已修改的问题。

我会使用security-constraint元素来阻止对所有未注册用户的访问。这将强制每个人进行身份验证,以便您的应用程序知道他们拥有的角色。 然后,您可以使用程序化安全性精细控制对各种资源的访问。

使用基本身份验证,我猜没有其他方法。如果要避免对基本用户进行身份验证,则需要使用表单身份验证并在后台以编程方式处理身份验证,即使他们不知道也可以使用HttpServletRequest#login()对其进行身份验证。

在这两种方式中,您都应该能够以您描述的方式设置权限。如果您想更顺利地处理未经授权的异常,最好删除@RolesAllowed注释,而是使用以下内容:

@GET
@Path("/{uuid}")
public Response getData(@PathParam("uuid") final String uuid, @Context SecurityContext sc) {
    if (sc.isUserInRole("MyRole")) {
        return result;
    } else {
        return notAllowedResult;
    }
}

答案 1 :(得分:2)

Roles-Allowed是一个EJB构造,与访问资源不一致,由资源安全约束处理。

不幸的是,这两个安全概念并不像它们应该那样进行网格划分,如果你没有获得授权(网络概念),而不是获得401,你会得到你正在接收的安全性异常(以及EJB概念) 。实际上,如果您使用RolesAllowed注释EJB Web服务并尝试访问具有无效角色的Web服务,我不知道您将收到什么错误。在这种情况下,我假设你会遇到SOAP错误。

EJB安全性是一个保护未经授权的人员的系统,但这是最后的努力。它假设任何将人员路由到方法调用的决定都已经预先完成。例如,没有高级方法来测试是否允许某个方法,而是只能调用它并捕获异常。

因此,严酷的事实超出了粗略的守门人,你想要利用程序化安全性。