Domanda

I have created a web service in netbeans with METRO. I modified my web service wsit config for using Usernametoken authentication (without encryption).

<?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());
    }
}

Now i need authorize user with his username and password and check his role (every method of web service has annotation RolesAllowed). I have created SOAP handler for my web service where I trying to get username and password from soap headers, but header doesnt contains this information (when i get this header in handler). Actually SOAP message looks like

<?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>

When I trying to extract header's child elements I'm getting only macAddress header (my custom header)

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

So. How can I access to wssecurity headers? Or maybe has another way to check user role before execution web service method?

È stato utile?

Soluzione

Instead of checking at your validator, store the username and password using ThreadLocal then apply your authentication roles within the service implementation as below. In my case, I used this approach to throw a custom exception.

My Validator:

/**
* @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;
}

}

My Service 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);
}

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top