无法使用Glassfish上的jax-ws进行身份验证

时间:2012-03-19 16:46:27

标签: java glassfish jax-ws basic-authentication

我一直在尝试创建一个使用SSL进行基本身份验证的java服务。配置SSL非常简单,但配置身份验证更加困难。每当我尝试调用标有@RolesAllowed注释的方法时,我都会收到以下异常......

Exception in thread "AWT-EventQueue-0" javax.xml.ws.soap.SOAPFaultException: javax.ejb.EJBAccessException
at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:111)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:129)
at $Proxy30.reverseString(Unknown Source)
at securitytestclient.SecurityTestClient.reverseStringSOAP(SecurityTestClient.java:305)
at securitytestclient.SecurityTestClient.buttonReverseActionPerformed(SecurityTestClient.java:217)
at securitytestclient.SecurityTestClient.access$000(SecurityTestClient.java:20)
at securitytestclient.SecurityTestClient$1.actionPerformed(SecurityTestClient.java:72)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener$Actions.actionPerformed(BasicButtonListener.java:303)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1661)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2879)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2926)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2842)
at java.awt.Component.processEvent(Component.java:6282)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1890)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:752)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1017)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:889)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:717)
at java.awt.Component.dispatchEventImpl(Component.java:4731)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2713)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
at java.awt.EventQueue.access$000(EventQueue.java:101)
at java.awt.EventQueue$3.run(EventQueue.java:666)
at java.awt.EventQueue$3.run(EventQueue.java:664)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:680)
at java.awt.EventQueue$4.run(EventQueue.java:678)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:677)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

我的服务器在Glassfish 3上使用JavaEE。它的功能在bean中定义如下......

package com.intproimp.testing.beans;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Local;
import javax.ejb.Stateless;

@Stateless(mappedName="ejb/StringOps/Bean")
@Local(StringOps.class)
public class StringOpsBean implements StringOps {

    @PermitAll
    @Override
    public String echoString(String str) {
        return str;
    }

    @RolesAllowed({"admin"})
    @Override
    public String reverseString(String str) {
        char[] input = str.toCharArray();
        char[] output = new char[input.length];
        for (int i = 0; i < output.length; i++) {
            output[i] = input[input.length - i - 1];
        }
        return new String(output);
    }
}

我已将登录配置添加到我的web.xml文件...

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>testing-frealm</realm-name>
</login-config>
<security-role>
    <description/>
    <role-name>admin</role-name>
</security-role>
<security-role>
    <description/>
    <role-name>user</role-name>
</security-role>

安全领域只是一个文件域,有一个用户(名称:“andrew”,传递:“12345”)。 我还将角色组映射添加到了我的glassfish-web.xml

<security-role-mapping>
    <role-name>user</role-name>
    <group-name>user</group-name>
</security-role-mapping>
<security-role-mapping>
    <role-name>admin</role-name>
    <group-name>admin</group-name>
</security-role-mapping>

在客户端,我有一个简单的swing应用程序来测试......

Swing Test Application

正在进行的调用是SOAP通道上的反向函数。 SOAP客户端组件是使用NetBeans通过New-&gt; WebService Client函数生成的。与反向按钮单击相关的操作是......

private void addAuthenticateionSOAP(StringOpsSOAP port) {
    ((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, fieldUsername.getText());
    ((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, fieldPassword.getText());
}

private String reverseStringSOAP(String str) {
    StringOpsSOAP_Service service = new StringOpsSOAP_Service();
    StringOpsSOAP port = service.getStringOpsSOAPPort();
    if (checkAuthentication.isSelected()) addAuthenticateionSOAP(port);
    return port.reverseString(str);
}

我确信只有一些我遗失的小东西,但我已经看了几天这个问题,但仍然没有找到它。

- 编辑 - 我意识到可能会有一些混乱,因为我没有发布我的WebService代码。包含String函数的EJB是通过SOAP WebService Bean ...

访问的
package com.intproimp.test.web;

import com.intproimp.test.beans.StringOps;
import javax.ejb.EJB;
import javax.jws.WebService;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;

@WebService(serviceName = "StringOpsSOAP")
@Stateless()
public class StringOpsSOAP {

    @EJB
    private StringOps ops;

    @WebMethod(operationName = "echoString")
    public String echoString(@WebParam(name = "str") String str) {
        return ops.echoString(str);
    }

    @WebMethod(operationName = "reverseString")
    public String reverseString(@WebParam(name = "str") String str) {
        return ops.reverseString(str);
    }
}

1 个答案:

答案 0 :(得分:2)

您需要在<security-constraint>添加web.xml,其中描述了允许哪些人访问某个网址。它在 Java EE 6教程中的Securing Web Applications中进行了描述。在你的情况下,它应该是这样的:

<security-constraint>  
<display-name>WebServiceSecurity</display-name>  

<web-resource-collection>  
    <web-resource-name>Authorized users only</web-resource-name>  
    <url-pattern>/yoururl</url-pattern>  
    <http-method>POST</http-method>
</web-resource-collection>  

<auth-constraint>       
    <role-name>user</role-name>
    <role-name>admin</role-name>
</auth-constraint>  

编辑:如果您通过将@webservice注释添加到类并使用@webmethod发布方法,将无状态会话bean设置为Web服务,这应该可以解决问题,正如dma_k在评论中所说的那样

编辑2: 从上面的链接:

  

指定安全限制

     

安全约束用于使用URL映射定义对资源集合的访问权限。

继续:

  

指定网络资源集

     

url-pattern 用于列出要保护的请求URI。许多应用程序都具有不受保护和受保护的资源。 要提供对资源的无限制访问权限,请不要为该特定请求URI配置安全性约束。

  

指定授权约束

     

授权约束建立了身份验证要求,并命名授权访问此安全约束声明的URL模式和HTTP方法的角色。 如果没有授权约束,则容器必须接受请求,而不需要用户身份验证。

所以,没有<security-constraint> =&gt;没有身份验证=&gt;没有可用的角色。

使用getUserPrincipal()中的审核或阅读信息(isUserInRole()WebServiceContext)进行验证。