服务器上的JAX-WS ws-security UsernameToken授权

时间:2012-07-19 07:12:00

标签: header jax-ws microsoft-metro ws-security authorize

我使用METRO在netbeans中创建了一个Web服务。我修改了我的web服务wsit配置以使用Usernametoken身份验证(没有加密)。

<?xml version="1.0" encoding="UTF-8"?> 
 <definitions 
 xmlns="http://schemas.xmlsoap.org/wsdl/" 
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="NewWebService" targetNamespace="http://test.org/" xmlns:tns="http://test.org/" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:fi="http://java.sun.com/xml/ns/wsit/2006/09/policy/fastinfoset/service" xmlns:tcp="http://java.sun.com/xml/ns/wsit/2006/09/policy/soaptcp/service" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:sc="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" 
 >
    <message name="hello"/>
    <message name="helloResponse"/>
    <portType name="NewWebService">
        <operation name="hello">
            <input message="tns:hello"/>
            <output message="tns:helloResponse"/>
        </operation>
    </portType>
    <binding name="NewWebServicePortBinding" type="tns:NewWebService">
        <wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameToken"/>
        <operation name="hello">
            <input></input>
            <output></output>
        </operation>
    </binding>
    <service name="NewWebService">
        <port name="NewWebServicePort" binding="tns:NewWebServicePortBinding"/>
    </service>
    <!-- Policy for Username Token with plaintext password, sent from client to server only -->
    <wsp:Policy wsu:Id="UsernameToken" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                    <wsp:Policy>
                        <sp:UsernameToken sp:IncludeToken=".../IncludeToken/AlwaysToRecipient"/>
                    </wsp:Policy>
                </sp:SupportingTokens>
                <wsss:ValidatorConfiguration wspp:visibility="private" xmlns:wsss="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
                    <wsss:Validator name="usernameValidator" classname="org.test.MyAuth"/>
                </wsss:ValidatorConfiguration>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
</definitions>

My PasswordValidator

package org.test;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidationException;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.Request;
public class MyAuth implements PasswordValidationCallback.PasswordValidator
{
    @Override
    public boolean validate(Request request) throws PasswordValidationException {
        PasswordValidationCallback.PlainTextPasswordRequest ptreq 
            = (PasswordValidationCallback.PlainTextPasswordRequest)request;
        //Database query
        return CheckUserInDateBase(ptreq.getPassword(), ptreq.getUsername());
    }
}

现在我需要用他的用户名和密码授权用户并检查他的角色(每个Web服务方法都有注释RolesAllowed)。我已经为我的Web服务创建了SOAP处理程序,我试图从soap头部获取用户名和密码,但是header不包含这些信息(当我在处理程序中获得此标头时)。 实际上SOAP消息看起来像

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <S:Header>
        <macAddress xmlns="http://ws.mkyong.com/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">F8-D1-11-01-36-20</macAddress>
        <wsse:Security S:mustUnderstand="1">
            <wsse:UsernameToken xmlns:ns15="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" xmlns:ns14="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns13="http://www.w3.org/2003/05/soap-envelope" wsu:Id="uuid_48e60f1c-aea9-4bcc-897f-ef661fe2895b">
                <wsse:Username>myusername</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypass</wsse:Password>
            </wsse:UsernameToken>
        </wsse:Security>
    </S:Header>
    <S:Body>
        <ns2:hello xmlns:ns2="http://test.org/">
            <name>aaaa</name>
        </ns2:hello>
    </S:Body>
</S:Envelope>

当我尝试提取标头的子元素时,我只得到macAddress标头(我的自定义标头)

@Override  
public boolean handleMessage(SOAPMessageContext context) {  
    Iterator i = context.getMessage().getSOAPPart().getEnvelope().getHeader().getChildElements();
    return true;
} 

因此。如何访问wssecurity标头?或者可能有其他方法在执行Web服务方法之前检查用户角色?

1 个答案:

答案 0 :(得分:1)

使用ThreadLocal存储用户名和密码,而不是检查验证器,然后在服务实现中应用您的身份验证角色,如下所示。就我而言,我使用这种方法抛出自定义异常。

我的验证员:

/**
* @author SaudAlajmi
*
*/
public class PasswordValidator implements PasswordValidationCallback.PasswordValidator {
/* I used this approach because they need to throw a custom exception in case of authentication failure, as far as I know there is no such way
 * to do it especially since the validator does not have access to the WebServiceContext, but this way and it is safe because every thread has
 * it is own copy and that's why I used ThreadLocal;
 */
private static final ThreadLocal<String> username = new ThreadLocal<String>();
private static final ThreadLocal<String> password = new ThreadLocal<String>();

public boolean validate(Request request) throws PasswordValidationException {
    PasswordValidationCallback.PlainTextPasswordRequest ptreq = (PasswordValidationCallback.PlainTextPasswordRequest) request;
    password.set(ptreq.getPassword());
    username.set(ptreq.getUsername());
    return true;
}
public static String getUsername() {
    String user = username.get();
    username.remove();
    return user;
}
public static String getPassword() {
    String pwd= password.get();
    password.remove();
    return pwd;
}

}

我的服务Impl:

String username = PasswordValidator.getUsername();
String password = PasswordValidator.getPassword();
if(username == null || !"test".equals(username) || password == null ||!"test".equals(password)){
faultInfo = new CommonErrorStructure();
faultInfo.setCode("KFSH000401");
faultInfo.setErrorText("Username/Password is incorrect");
faultInfo.setRaisedBy("PatientRecordService");
throw new GetPatientRecordError("Authentication Failure", faultInfo);
}

参考: Retrieve plaintext WS-Security password at service endpoint with Metro + WSIT?