2012-03-19 62 views
1

我一直在嘗試創建使用基於SSL的基本身份驗證的java服務。配置SSL非常簡單,但配置身份驗證更是一個問題。任何時候,我嘗試調用標有@RolesAllowed批註我收到以下異常的方法...無法使用Glassfish上的jax-ws進行身份驗證

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> 

安全領域只是一個文件的境界與一個用戶(名稱:「安德魯」,道:「 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客戶端組件是通過New-> WebService Client函數與NetBeans一起生成的。而與反向按鈕點擊相關的操作是......

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代碼。包含字符串函數是通過SOAP的WebService豆訪問EJB ...

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); 
    } 
} 
+0

也許,GlassFish是做一些魔術,但我不會期望:您已經發布的服務和EJB,但調用它作爲SOAP WS。你或者稱其爲遠程EJB(並按照EJB世界上認證遊戲),或使用JSR-181註釋發佈WS(參見[示例](https://community.jboss.org/wiki/JBWS181HelloWorld)),即在您想要作爲SOAP發佈的每種方法中的每個方法上的實現類和@ @ WebMethod上的'@ WebService'。附:有興趣研究一下'EJBAccessException'。 – 2012-03-20 08:17:54

+0

我應該澄清一下,Web服務註釋類使用EJB。我將編輯我的問題以添加代碼。 – 2012-03-20 15:26:41

+0

你能解決這個問題嗎? – TPete 2012-03-23 12:53:43

回答

2

你需要一個<security-constraint>添加到您的web.xml描述誰被允許訪問某個網址。在Securing Web ApplicationsJava EE 6教程中對此進行了描述。你的情況應該是這樣的:

<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註釋類和發佈做,如果你有讓你的無狀態會話bean Web服務,訣竅正如dma_k在評論中所說的那樣使用@webmethod的方法。

編輯2: 從上面的鏈接:

指定安全約束

安全約束被用來定義訪問權限使用他們的URL映射資源的集合。

而且上:

指定Web資源集合

url-pattern的用於列出的請求被保護URI。許多應用程序都有不受保護和受保護的資源。 要提供對資源的無限制訪問,請不要爲該特定請求URI配置安全約束。

和:

指定授權約束

授權約束規定了認證,並正式授權該安全訪問聲明的URL模式和HTTP方法角色的要求約束。 如果沒有授權約束,容器必須接受請求而不要求用戶驗證。

因此,沒有<security-constraint> =>沒有身份驗證=>沒有角色可用。

使用審覈或從WebServiceContext讀取信息(getUserPrincipal(),isUserInRole()),以驗證這一點。

+0

@RolesAllowed批註即上StringOpsBean.reverseString(字符串)並有效地阻止訪問該方法調用。問題是Glassfish似乎不接受用戶登錄。 – 2012-03-20 15:32:33

+1

@AndrewRademacher你想限制對該方法的訪問。爲此,您需要指定安全約束。沒有它,不需要認證。沒有身份驗證,就沒有用戶角色,這就是爲什麼沒有用戶被授予訪問該方法的原因。順便說一句:激活審計確實幫助我設置安全性。 – TPete 2012-03-20 19:44:00

+0

所以,如果我要添加一個約束,其路徑爲/ *,並且它的角色是用戶。那麼@RolesAllowed({「admin」})就會堆疊在上面嗎?所以要調用reverseString,你必須既是用戶又是管理員? – 2012-03-20 23:51:54