5 Replies Latest reply: Oct 23, 2009 11:19 AM by Ravi Jegga RSS

    Problems with JAX-WS and basic authentication

    726437
      Hi,

      I use weblogic 10.0 and have developed a JAX-WS client that access a remote web service that requires basic authentication. Since the wsdl also required basic authentication, this turned out to be quite a pickle to solve in weblogic, although it was very easy to do using just javaee5.

      This code:
      MyService service = new MyService(
          new URL("http://myhost/myfile/myws?wsdl"), 
          new QName("http://someqname", "someservice", XMLConstants.DEFAULT_NS_PREFIX));
      Failes because the wsdl location requires basic authentication. So I added this:
      Authenticator.setDefault(new Authenticator() {
          @Override
          protected PasswordAuthentication getPasswordAuthentication() {
              return new PasswordAuthentication("user", "pwd".toCharArray());
          }
      });
      Which also failes because the weblogic URLStreamHandler seems to ignore authentication. In order to solve this I need to use a different URLStreamHandler, like this:
      MyService service = new MyService(
          new URL("http", "myhost", 80, "/myfile/myws?wsdl", new sun.net.www.protocol.http.Handler()), 
          new QName("http://someqname", "someservice", XMLConstants.DEFAULT_NS_PREFIX));
      The code above solves the problem, and I can use the authenticator as normal. However this seems like an unnecassary work around, and I wonder how weblogic wants to solve this? What is the propper way to solve this problem in weblogic?

      Another possible solution I tried for this, was to use a local wsdl file, instead of the remote one. This also works in javaee5, but in weblogic the code tries to access the webservice at the local file location, not the service location. Is there any other solution to this problem that is more weblogic native?

      Regards
      Morten
        • 1. Re: Problems with JAX-WS and basic authentication
          648859
          user12011980 wrote:
          Hi,

          I use weblogic 10.0 and have developed a JAX-WS client that access a remote web service that requires basic authentication. Since the wsdl also required basic authentication, this turned out to be quite a pickle to solve in weblogic, although it was very easy to do using just javaee5.
          IMHO, WSDL is not proper to require basic auth. WSDL is used to expose your service. It should be able to access by anyone.
          This code:
          MyService service = new MyService(
          new URL("http://myhost/myfile/myws?wsdl"), 
          new QName("http://someqname", "someservice", XMLConstants.DEFAULT_NS_PREFIX));
          Failes because the wsdl location requires basic authentication. So I added this:
          true
          Authenticator.setDefault(new Authenticator() {
          @Override
          protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication("user", "pwd".toCharArray());
          }
          });
          Which also failes because the weblogic URLStreamHandler seems to ignore authentication. In order to solve this I need to use a different URLStreamHandler, like this:
          MyService service = new MyService(
          new URL("http", "myhost", 80, "/myfile/myws?wsdl", new sun.net.www.protocol.http.Handler()), 
          new QName("http://someqname", "someservice", XMLConstants.DEFAULT_NS_PREFIX));
          The code above solves the problem, and I can use the authenticator as normal. However this seems like an unnecassary work around, and I wonder how weblogic wants to solve this? What is the propper way to solve this problem in weblogic?
          I think it wouldn't enable weblogic URLStreamHandler if your client is a standalone client(not a server side client).
          >
          Another possible solution I tried for this, was to use a local wsdl file, instead of the remote one. This also works in javaee5, but in weblogic the code tries to access the webservice at the local file location, not the service location. Is there any other solution to this problem that is more weblogic native?
          Sound like a bug, could you elaborate your case?
          >
          Regards
          Morten
          • 2. Re: Problems with JAX-WS and basic authentication
            726437
            LJ wrote:
            IMHO, WSDL is not proper to require basic auth. WSDL is used to expose your service. It should be able to access by anyone.
            I agree, but when dealing with foreign web service providers, I have to adapt to their way, even though it's wrong.
            Another possible solution I tried for this, was to use a local wsdl file, instead of the remote one. This also works in javaee5, but in weblogic the code tries to access the webservice at the local file location, not the service location. Is there any other solution to this problem that is more weblogic native?
            Sound like a bug, could you elaborate your case?
            I created two clients for testing this. One standalone using just javaee, and one EJB application to be deployed on the weblogic servers (which is the one I need working). I figured that I should be able to just use a local version of the WSDL, since the URL to the actual service is in the WSDL.
            MyService service = new MyService(
                new URL("http://localhost/myfile/mylocal.wsdl"), 
                new QName("http://someqname", "someservice", XMLConstants.DEFAULT_NS_PREFIX));
            This worked fine using the standalone client. But when I deploy this solution on weblogic, I get this error:
            javax.xml.ws.WebServiceException: java.io.FileNotFoundException: Response: '403:
             Forbidden' for url: 'http://localhost/myfile/mylocal.wsdl'
                    at com.sun.xml.ws.wsdl.WSDLContext.<init>(WSDLContext.java:68)
                    at com.sun.xml.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:207)
                    at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:165)
                    at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:49)
                    at weblogic.wsee.jaxws.spi.WLSProvider.createServiceDelegate(WLSProvider.java:18)
                    at javax.xml.ws.Service.<init>(Service.java:57)
                    ...
            Caused by: java.io.FileNotFoundException: Response: '403: 
             Forbidden' for url: 'http://localhost/myfile/mylocal.wsdl'
                    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:476)
                    at weblogic.net.http.SOAPHttpURLConnection.getInputStream(SOAPHttpURLConnection.java:36)
                    at java.net.URL.openStream(URL.java:1007)
                    at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:656)
                    at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parseWSDL(RuntimeWSDLParser.java:152)
                    at com.sun.xml.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:99)
                    at com.sun.xml.ws.wsdl.WSDLContext.<init>(WSDLContext.java:65)
                    ...
            It does seem like a bug, and my first thought was that the weblogic ServiceDelegate...
            weblogic.wsee.jaxws.spi.WLSProvider.createServiceDelegate
            ...does not use the service location in the WSDL, but rather assumes that the WSDL location also contains the service. This is just my guess though.

            Regards
            Morten
            • 3. Re: Problems with JAX-WS and basic authentication
              648859
              I think weblogic.wsee.jaxws.spi.WLSProvider.createServiceDelegate is not the cause. Using weblogic.net.http.SOAPHttpURLConnection is expected in container environment, container needs to control all the outbound connections. But I am not sure why it doesn't call back user authenticator.
              My suggestion: always use local copy of WSDL.
              • 4. Re: Problems with JAX-WS and basic authentication
                726437
                LJ wrote:
                My suggestion: always use local copy of WSDL.
                Which is also what I attempted, but that resulted in the same error mentioned above. As also mentioned, it works perfectly using just javaee5, but fails under weblogic 10.0. Maybe this is resolved in 10.3.

                However, I would still like to know what the correct method in weblogic to solve basic authentication is, since using Authenticator doesnt work.
                • 5. Re: Problems with JAX-WS and basic authentication
                  Ravi Jegga
                  Hi Morten
                  Just incase if you still have this issue, you can try this approach. I used it recently. I have a BPEL WebService deployed on Oracle SOA. That I need to consume in my portal side in a portlet within a pageflow java class

                  http://download.oracle.com/docs/cd/E12840_01/wls/docs103/webserv_adv/handlers.html

                  I used Handlers approach to intercept the outgoing request and add this security header with username and password token.

                  I created a custom Handler class and implemented the logic to add security header in this method: handleMessage(SOAPMessageContext messageContext). I used standard sun jdk imports and nothing specific to weblogic. Then add this Handler to my Service binding provider.

                  *** To add custom handler to your service object ***
                  // Set the Custom Handler to set the Security SOAP Header. See IoDHandler1 class for more details
                  ......
                  BindingProvider bindingProvider = (BindingProvider) aIoDPort;

                  Binding aBinding = bindingProvider.getBinding();
                  List<Handler> allHandlers = aBinding.getHandlerChain();
                  allHandlers.add(new IoDHandler1());
                  aBinding.setHandlerChain(allHandlers);
                  ***********
                  **** Code snippet in Custom Handler1 class *****
                  import javax.xml.namespace.QName;
                  import javax.xml.ws.handler.soap.SOAPHandler;
                  import javax.xml.ws.handler.MessageContext;
                  import javax.xml.ws.handler.soap.SOAPMessageContext;
                  import javax.xml.soap.*;

                  public boolean handleMessage(SOAPMessageContext messageContext) {
                       Boolean outboundProperty = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

                       if (outboundProperty.booleanValue()) {
                            //System.out.println("IoDHandler1::handleMessage() -> Outbound Message");

                            try {
                                 SOAPMessage soapMessage = messageContext.getMessage();
                                 SOAPPart soapPart = soapMessage.getSOAPPart();
                                 SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
                                 //SOAPBody soapBody = soapEnvelope.getBody();
                                 //SOAPHeader soapHeader = soapEnvelope.getHeader();

                                 //soapEnvelope.addNamespaceDeclaration("soap", "http://schemas.xmlsoap.org/soap/envelope/");
                                 soapEnvelope.addNamespaceDeclaration("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

                                 SOAPHeader header = soapEnvelope.addHeader();

                                 String namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
                                 SOAPElement securityElement = header.addHeaderElement(soapEnvelope.createName("Security", "wsse", namespace));

                                 securityElement.addNamespaceDeclaration("", namespace);
                                 //securityElement.addNamespaceDeclaration("env", "http://schemas.xmlsoap.org/soap/envelope/");

                                 SOAPElement usernameTokenElement = securityElement.addChildElement(soapEnvelope.createName("UsernameToken", "wsse", namespace));
                                 usernameTokenElement.addNamespaceDeclaration("", namespace);

                                 SOAPElement usernameElement = usernameTokenElement.addChildElement(soapEnvelope.createName("Username"));
                                 SOAPElement passwordElement = usernameTokenElement.addChildElement(soapEnvelope.createName("Password"));

                                 // For Testing Purposes only hardcoded this username and password values. Later on this may be set dynamically
                                 usernameElement.setValue("xxxxx");
                                 passwordElement.setValue("yyyyy");

                                 soapMessage.saveChanges();

                                 File aFile = new File("webServiceRequest.xml");
                                 FileOutputStream aFOS = new FileOutputStream(aFile);
                                 soapMessage.writeTo(aFOS);

                            } catch (Exception e) {
                                 // For now just ignore the errror and invoke the WebService without this Header Element. Anyhow the backend BPEL
                                 // will kick back with error like username/password not found etc...
                                 System.out.println("IoDHandler1::handleMessage() -> Inside CATCH Error Block -> IGNORE FOR NOW AND CONTINUE...");
                                 e.printStackTrace();
                            }
                       } else {
                            //System.out.println("IoDHandler1::handleMessage() -> Inbound Message");
                       }
                       //System.out.println("IoDHandler1::handleMessage() -> Response: " + messageContext.getMessage().toString());
                       return true;
                  }

                  ************

                  Goud