WS-Security Axis2, работающая на сервере приложений Java EE

У меня есть веб-службы Axis2, работающие на сервере приложений (например, JBoss, WebSphere и Weblogic), и до сих пор я передаю данные пользователя в запросе и проверяю подлинность пользователя перед его обработкой.

Следующий шаг - я хочу делегировать бит аутентификации серверу приложений Java EE, и после аутентификации сервер приложений должен передать принцип UserPrinciple, который я буду использовать в качестве контекста для выполнения запроса.

Я не уверен, правильно ли я задал вопрос? Я думаю, что я смешиваю аутентификацию WebContainer с вещами WS-Security.

Может кто-нибудь, пожалуйста, укажите мне правильное направление с некоторой документацией, которую я могу сослаться как руководство по запуску.

2 ответа

Решение

Хорошо, я попробовал решение, и оно работало до некоторой степени. Вот подробности;

Создан TestService со следующими services.xml

<serviceGroup>
    <service name="TestWebService" scope="application" targetNamespace="http://TestServiceWs"> 
        <schema schemaNamespace="http://TestServiceWs"/>
        <description>Test POJO Axis2 AAR deployment</description>
        <parameter name="ServiceClass">test.TestServiceWS</parameter>
        <messageReceivers>
            <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
                class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
            <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
                class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
        </messageReceivers>
    </service>

    <module ref="rampart" />

    <parameter name="InflowSecurity">
      <action>
        <items>UsernameToken Timestamp</items>
        <passwordCallbackClass>test.PWHandlerServer</passwordCallbackClass>
      </action>
    </parameter>
</serviceGroup>

Реализован PWHandlerServer.java

package test;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class PWHandlerServer implements CallbackHandler {

    // the username and password we expect incoming WS calls to use
    private String user = "wsuser";
    private String pwd = "wspwd";

    public void handle (Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                System.out.println("identifier: "+pc.getIdentifer()+", usage: "+pc.getUsage());

                if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN) {
                    // for passwords sent in digest mode we need to provide the password,
                    // because the original one can't be un-digested from the message

                    // we can throw either of the two Exception types if authentication fails
                    if (! user.equals(pc.getIdentifer()))
                        throw new IOException("unknown user: "+pc.getIdentifer());

                    // this will throw an exception if the passwords don't match
                    pc.setPassword(pwd);

                } else if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {
                    // for passwords sent in cleartext mode we can compare passwords directly

                    if (! user.equals(pc.getIdentifer()))
                        throw new IOException("unknown user: "+pc.getIdentifer());

                    // we can throw either of the two Exception types if authentication fails
                    if (! pwd.equals(pc.getPassword()))
                        throw new IOException("password incorrect for user: "+pc.getIdentifer());
                }
                // If everything is OK then set the context and move on
                TestRequestContext ctx = new TestRequestContext(pc.getIdentifer());
                TestRequestContext.setRequestContext(ctx);

            } else {
                throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
            }
        }
    }
}

Реализован TestRequestContext

package test;


class TestRequestContext {
    private final static ThreadLocal<TestRequestContext> currentContext = new ThreadLocal<TestRequestContext>();

    public static void setRequestContext(TestRequestContext context) {
        currentContext.set(context);
    }

    public static TestRequestContext getRequestContext() {
        return currentContext.get();
    }

    public static void clearRequestContext() {
        currentContext.remove();
    }

    private String userPrincipal;

    public TestRequestContext(String principal) {
        this.userPrincipal = principal;
    }

    public String getUserPrincipal(){
        return this.userPrincipal;
    }
}

Теперь я должен иметь возможность получить доступ к моему TestRequestContext.getUserPricipal() в моем классе веб-службы и передать его в БД для транзакций и переключения контекста безопасности. Единственная проблема - когда я пытаюсь получить доступ к сервису через SoapUI, он дает мне следующее исключение;

    15:07:34,924 INFO  [STDOUT] identifier: wsuser, usage: 5
15:08:48,081 INFO  [STDOUT] [ERROR] WSDoAllReceiver: security processing failed (actions mismatch)
org.apache.axis2.AxisFault: WSDoAllReceiver: security processing failed (actions mismatch)
        at org.apache.rampart.handler.WSDoAllReceiver.processBasic(WSDoAllReceiver.java:344)
        at org.apache.rampart.handler.WSDoAllReceiver.processMessage(WSDoAllReceiver.java:86)
        at org.apache.rampart.handler.WSDoAllHandler.invoke(WSDoAllHandler.java:72)
        at org.apache.axis2.engine.Phase.invoke(Phase.java:318)
        at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:254)
        at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:160)
        at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:173)
        at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:144)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
        at java.lang.Thread.run(Thread.java:619)

В SoapUI я просто использую вкладку "Auth", чтобы установить имя пользователя и пароль и вызвать? мне нужно настроить что-нибудь еще до вызова.

Кроме того, подход к использованию ThreadLocal является правильным, или я могу получить доступ к этому принципу как-то иначе?

Благодарю.

Вы можете также передать имя пользователя в заголовке SOAP в следующем формате. Вы можете получить доступ к этому в операции, прежде чем авторизоваться. Вам может не потребоваться класс TestRequestContext для хранения имени пользователя. Пожалуйста, дайте мне знать, если кто-то не согласен.

MessageContext msgContext = MessageContext.getCurrentMessageContext();                   
// Getting HttpServletRequest from Message Context 
String username = (String)msgContext 
                           .getProperty(RampartMessageData.USERNAME);
Другие вопросы по тегам