Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAX-WS Password Type PasswordText

I've got a simple command line Java JAX-WS app to test a SOAP request, but the server is expecting the Password Type to be PasswordText and I'm stumped on how to set this...

The code looks like so:

@WebServiceRef
private static final HelloService helloService = new HelloService(url, new QName(
        URL, "HelloService"));

public static void main(final String... args) {

    try {
        final HelloPort helloPort = helloService.getHelloPort();
        final BindingProvider hB = ((BindingProvider) helloPort);
        hB.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                                   END_POINT_ADDRESS);
        hB.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,
                                   USERNAME);
        hB.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,
                                   PASSWORD);
        ...

I've tested the request using SOAP-UI so I know it's working. Any help on setting the password type would be appreciated.

Thanks.

like image 794
marktucks Avatar asked Jun 22 '10 18:06

marktucks


2 Answers

That will set the username and password for Basic HTTP authentication. If you've tested it in SoapUI, I'm guessing the 'PasswordText' value you speak of is the 'WSS-Password Type' in the request details pane. That sets WSS security, not HTTP security.

With JAX-WS in Java6 you need to attach a SOAPHandler to inject the WSS-Usertoken into the SOAP Header. There are plenty of bits and bobs about this round the net, but I couldn't find one single link to post, so here's some code instead to get you going...

To add a handler you need something like:

final Binding binding = ((BindingProvider) servicePort).getBinding();
List<Handler> handlerList = binding.getHandlerChain();
if (handlerList == null)
    handlerList = new ArrayList<Handler>();

handlerList.add(new SecurityHandler());
binding.setHandlerChain(handlerList); // <- important!

Then the SecurityHandler class will do the deed. Handlers are general things and get called for both successful messages and for faults, but perhaps more importantly they get called in both message directions - for the outgoing request and then again for the incoming response. You only want to handle outgoing messages. So you'll need something like:

public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

    ...

    @Override
    public boolean handleMessage(final SOAPMessageContext msgCtx) {

        // Indicator telling us which direction this message is going in
        final Boolean outInd = (Boolean) msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        // Handler must only add security headers to outbound messages
        if (outInd.booleanValue()) {
            try {
                // Get the SOAP Envelope
                final SOAPEnvelope envelope = msgCtx.getMessage().getSOAPPart().getEnvelope();

                // Header may or may not exist yet
                SOAPHeader header = envelope.getHeader();
                if (header == null)
                    header = envelope.addHeader();

                // Add WSS Usertoken Element Tree 
                final SOAPElement security = header.addChildElement("Security", "wsse",
                        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");
                userToken.addChildElement("Username", "wsse").addTextNode("MyWSSUsername");
                userToken.addChildElement("Password", "wsse").addTextNode("MyWSSPassword");

            } catch (final Exception e) {
                LOG.error(e);
                return false;
            }
        }
        return true;
    }

    ...
    // Other required methods on interface need no guts
}

I've made a few assumptions here, but hopefully it'll get you going!

Kind regards.

like image 78
SimonB Avatar answered Nov 12 '22 06:11

SimonB


If you implement SOAPHandler interface, the method msgCtx.getMessage() will render the entire XML, and if you are working with big files you will have Out of Memory errors. I tested with UsernameToken authentication on JAX-WS client and it works:

String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
String PASSWORD_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
String AUTH_PREFIX = "wss";

MyService service = new MyService();
MyServicePort port = service.getMyServicePort();

try {
    SOAPFactory soapFactory = SOAPFactory.newInstance();
    SOAPElement security = soapFactory.createElement("Security", AUTH_PREFIX, SECURITY_NS);
    SOAPElement uToken = soapFactory.createElement("UsernameToken", AUTH_PREFIX, SECURITY_NS);
    SOAPElement username = soapFactory.createElement("Username", AUTH_PREFIX, SECURITY_NS);
    username.addTextNode("username");

    SOAPElement pass = soapFactory.createElement("Password", AUTH_PREFIX, SECURITY_NS);
    pass.addAttribute(new QName("Type"), PASSWORD_TYPE);
    pass.addTextNode("password");

    uToken.addChildElement(username);
    uToken.addChildElement(pass);
    security.addChildElement(uToken);

    Header header = Headers.create(security);
    ((WSBindingProvider) port).setOutboundHeaders(header);

    // now, call webservice

} catch (SOAPException ex) {
    ex.printStackTrace();
}

Edit: You should add the "rt.jar" from jre to classpath.

like image 28
cleison Avatar answered Nov 12 '22 05:11

cleison