24 Replies Latest reply on Jan 22, 2015 1:10 PM by jross101

    Basic authentication when calling a web service

    ggcambridger
      I am attempting to call a web service using ActionScript. The web service provider requires that I use HTTP Basic Authentication to communicate my SOAP requests. I cannot seem to get this done in ActionScript. If I instantiate a WebService object and call its SetCredentials method, I get an error "Authentication not supported on DirectHTTPChannel (no proxy)". I have the WebService object's useProxy property set to true. HELP!
        • 1. Re: Basic authentication when calling a web service
          ggcambridger Level 1
          Adobe, please help!

          I have seen this question posed five other times in this forum, but I cannot find an answer anywhere. The problem itself is simple: I want to call a SOAP-based Web Service that is protected on its server via HTTP Basic Authentication.

          I would like to use ActionScript like the following, but I cannot ever get it to work. Like the others who have posted this same question, I have tried all permutations of setCredentials, setRemoteCredentials, and useProxy, but I cannot figure out how to specify the username/password combo that is required by the server when it performs its Basic HTTP Authentication.

          This seems to be a common problem without a solution -- can anyone help, please?

          Thanks in advance

          -- Greg

          var ws:WebService;

          function main () : void
          {
          ws = new WebService ();

          ws.addEventListener("load", wsdlLoadHandler);
          ws.loadWSDL("myWsdlFile.wsdl");
          }

          function wsdlLoadHandler (event:LoadEvent) : void
          {
          ws.addEventListener (ResultEvent.RESULT, wsComplete);
          ws.addEventListener (FaultEvent.FAULT, wsFault);

          ws.someFunction.addEventListener (ResultEvent.RESULT, wsComplete);
          ws.someFunction.addEventListener (FaultEvent.FAULT, wsFault);

          ws.endpointURI = "url_to_some_web_service_that_requires_basic_HTTP_authentication";

          ws.someFunction (3.14159);
          }

          private function wsComplete (event:ResultEvent) : void
          {
          var xyz:int = 5;
          }

          private function wsFault (event:FaultEvent) : void
          {
          var xyz:int = 5;
          }
          • 2. Re: Basic authentication when calling a web service
            roland.schroth
            I searched quite long for a solution to this too.

            But it seems there is none.

            I hope this will no longer be an issue in Flex 3 because the problem is common and quite trivial and I don't see a reason why this should not be possible with webservices.

            Kind regards, Roland
            • 3. Re: Basic authentication when calling a web service
              ggcambridger Level 1
              Adobe, help! It seems that others have tried in vain to solve this problem -- it's a very basic problem: How do I call a Web Service using HTTP basic authentication? If I had the source to the WebService class I could add the HTTP authentication header myself inside there... but there must be some other way!

              HELP!
              • 4. Re: Basic authentication when calling a web service
                ntsiii Level 3
                One other way is to proxy the webservice call through a server-side platform.

                I never call any data service directly from Flex.

                Tracy
                • 5. Re: Basic authentication when calling a web service
                  ggcambridger Level 1
                  Hi Tracy, thanks for the input. I am working with a third party and the client application needs to call their web services. Yes, I could (and have) proxied the call through my own server (I take the POST in my own server, and relay it on to the third party services -- C# does not have a problem calling a web service with basic authentication). But the third party that supplies this web service operates a huge server farm that can literally service hundreds of thousands of transactions per minute. I would have to build my own farm of proxy servers just to work around a shortcoming in Flex (and the apparent unwillingness of Adobe to even acknowledge it). My farm would have to be capable of matching the level of service of the third party, and this would would be very expensive to build and operate (even though all it would be doing is adding an authentication header and then relaying requests on to the third party web service)

                  You state that you always call through a proxy server instead of calling a web service directly from Flex. Is there some other advantage to this approach that I am missing?

                  Thanks again!

                  Greg
                  • 7. Re: Basic authentication when calling a web service
                    ggcambridger Level 1
                    Unfortunately, this post discusses HTTP Basic Authentication for the HTTPService class, which does not process SOAP like the WebService class does. In fact, one of the replies in the thread you pointed me at is another poor guy, with the exact same question, who is also being ignored by Adobe. There are many users with this problem -- Adobe should help us out, here!

                    (From the thread suggested by the previous poster:)

                    quote:

                    Hi Abdul,
                    I am looking at a similar problem with slightly different twist. It is best described by a question posted here http://192.150.14.120/cfusion/webforums/forum/messageview.cfm?catid=582&threadid=1160651&e nterthread=y

                    "I would like a standalone Flex 2.0 SWF to be able to use a set of 3rd party webservices protected by basic authentication. Is it possible? If yes, could someone put a simple step-by-step example up? I just can't see anyway to do this from the livedocs entry."

                    The stuff livedocs and other places seem to imply a Flex or CF server in the back-end.

                    What you have could be used to address this but I am not able to get it to work with the WebService object. I am using your code to do basic HTTP authentication then invoke calls using the WebService object. Though the authentication suceeds I still get prompted for user/password when I make the WebService call.

                    • 8. Re: Basic authentication when calling a web service
                      ggcambridger Level 1
                      Bump -- Adobe, can you help?
                      • 9. Re: Basic authentication when calling a web service
                        Skitsanos
                        Guys,

                        the easiest way to solve this problem is to use "inline" basic authentication this way:

                        <mx:Webservice wsdl=" http://{ws_username}:{ws_password}@your_ws_url" />

                        It works 100%, but you have to be be aware of two things:
                        1) you need your ws_username and ws_password must be URLEncode'd, so for example "@" character of email address will turn into %40 and so...

                        2) if someone will want to sniff for your password and user name, he can do it very easy by looking into "Authentication" HTTP header same way as u URL and extract your credentials, all you have to do is Base64 decode.

                        Hope this helps. if you have more questions, drop me a line or gtalk to me on info [at] skitsanos [dot] com

                        Cheers,
                        Evi Skitsanos.
                        • 10. Re: Basic authentication when calling a web service
                          roland.schroth Level 1
                          Hi Evi,

                          that workaround does not help, if the WSDL is loaded from another location than the one that is called for the WebService.

                          I currently have a scenario where i have the WSDLs deployed together with the application because they are not provided at the URL where the WebService itself is located. This might be a quite special case but even these special cases happen to exist.

                          Regards, Roland
                          • 11. Re: Basic authentication when calling a web service
                            rohail99
                            I am in the same boat. I am calling a WCF service from FLEX and I need to supply userID and password to authenticate the user. Has anyone figured out a solution to this problem?
                            • 12. Re: Basic authentication when calling a web service
                              JoshBeall
                              I would like to see a clear resolution to this as well. I posted about my attempts to use the setCredentials method (in this case, to see if it worked with Basic authentication).

                              I haven't tried using basic authentication by embedding the username and password in the WSDL URL. I'll try that next -- but I would still like to know what the setCredentials method is used for, and why I'm getting the "Authentication not supported on DirectHTTPChannel" error -- where/when *is* authentication support, and how do I set up my web service to use authentication?

                              • 13. Re: Basic authentication when calling a web service
                                JoshBeall Level 1
                                As mentioned by Pete from Adobe, the setCredentials (and setRemoteCredentials) are not useful in instances where you are not using Flex Data Services (now rebranded LiveCycle Data Services).

                                I did not have much success with Basic authentication via the "inline" method described by Skitsanos in this thread. It didn't work at all in IE, and even in browsers where it worked, if the username/password is wrong, the Flex UI can't intercept the login failure, and the user gets that ugly login popup. I might be able to live with the latter problem, but the former is a showstopper. Basic authentication is out until I can get it to work in IE.

                                I am hopeful that we will get basic authentication support added in the future. But only time will tell. In the mean time I am looking into using SOAP headers... however, so far, I've not had any luck with that either (the SOAP headers I attach to the web service call don't actually get sent -- I can see this by using Wireshark to view the SOAP XML going over the wire).
                                • 14. Basic authentication when calling a web service
                                  nijlz
                                  This is a possible solution:

                                  You first login with HTTPService with Basic Authentication
                                  <mx:HTTPService url=" http://{username.text}:{password.text}@www..." />

                                  and then you can use the WebService as usual
                                  <mx:WebService wsdl=" http://www..."/>

                                  I hope this will help. The only thing is, that it is not working in InternetExplorer, just in Firefox.
                                  • 15. Re: Basic authentication when calling a web service
                                    TOdd_23523523 Level 1
                                    I use something similar to nijlz above, but we're in control of our own servers. Our server is setup so that the http handler creates and manages the user sessions, and once the user has a valid session, they can access the WebServices behind that. And to use from Flex, we using an HTTPService call first, and then we make calls to WebServices.

                                    A lot of what everyone is talking about with not accessing WSDL files seems more to do with the Web Service Provider's limiting factors, than Flex per say. I'm finding this a lot with people who only consume and produce Web Services in a .NET only environment. Web Services in .NET work really well with itself, but when it comes to accessing from a variety of third-party clients...not so much, mostly because the people who created them live in a Microsoft vacuum. This isn't just a Flex thing, but I see it when trying to consume various Web Services from various technologies. It's probably why people are getting frustrated and moving to a simpler RESTful style request/response. (Sorry to go a little off-topic.)
                                    • 16. Re: Basic authentication when calling a web service
                                      andrew.morrison
                                      Another possible hack is to pass the credentials as a GET parameter, and have your endpoint web server convert the parameter into the Authentication HTTP header.

                                      In flex-land, modify the URL of the webservice as follows:

                                      public function
                                      setCredentials(username;String, password:String):void
                                      {
                                      var base64Encoder:Base64Encoder = new Base64Encoder();
                                      base64Encoder.encodeUTFBytes(username+':'+password+"\n");
                                      endpointURI = endpointURI + '?' + base64Encoder.toString();
                                      }

                                      In apache-land, add the following directives to convert the GET parameter to a header:

                                      SetEnvIfNoCase Authorization ^.*$ NO_Authorization
                                      RequestHeader add Authorization "Basic ${QUERY_STRING}e" env=NO_Authorization

                                      (delete the newline before env=... or Apache will complain)
                                      • 17. Re: Basic authentication when calling a web service
                                        Wu_Xiao
                                        Have done a lot of research of this last week. Here are my findings: there is no way to programmatically invoke a web service when its wsdl is protected by http basic authentication in Flex (2, 3) and this CAN be done for http services. If looking at following code to access a web service and a http service:
                                        var ws1:WebService = new WebService();
                                        ws1.httpHeaders = {Authorization:"Basic a2F0emo6a2F0ejAxNmoo="};
                                        ws1.wsdl = " http://hostname/Temp-WS-context-root/WSWSSoapHttpPort?wsdl";
                                        ws1.loadWSDL();
                                        ws1.superTest.send();
                                        ...
                                        var hs1:HttpService= new HttpService();
                                        hs1.httpHeaders = {Authorization:"Basic a2F0emo6a2F0ejAxNmoo="};
                                        hs1.method = "GET";
                                        hs1.url = " http://hostname/Temp-WS-context-root/test.jsp";
                                        hs1.send();

                                        Both have the header for basic authentication, the second succeeds and the first one pops up the login dialog. After went through the flex code, I found flex invoking a web service by 2 http service calls: one for wsdl and one for the endpoint. The issue is the one loading the wsdl does not take the header for basic authentication! Take look the initializeService method of the XMLLoader class (superclass of wsdlloader) where the new http service for load wsdl is created. Also to verify this, you may unprotect the wsdl file. I am surprised that adobe concluded this bug (https://bugs.adobe.com/jira/browse/SDK-12198) as "cannot fix" due to a flash player bug. I have to say my player sends http get request with headers just fine. I believe this is still an overlooked flex code issue.


                                        • 18. Re: Basic authentication when calling a web service
                                          Wu_Xiao Level 1
                                          Some corrections. It is true that flash player 9 does not allow setting security headers in a httpservice. But Air does. So in general flex should pass the security header to the wsdl loading httpservice.
                                          • 19. Re: Basic authentication when calling a web service
                                            Roadman730
                                            i got heahache about this problem too.
                                            Could you anyone summarize a workable solution for me?
                                            I am using Flex 2.0 to call a web service in .NET platform with Basic Authentication enabled.
                                            • 20. Re: Basic authentication when calling a web service
                                              gkohen
                                              Contrary to what most people have been using here (Directly instansiating the WebService object), I've used the auto-generated files from the WSDL importer. I was going nuts since any of the "Authorization" headers I was pushing in my requests were going to the server (Which is what needed for HTTP basic authorization). So I dug a bit deeper into the code generated for me by the Flex builder and realized that the generated code, although was supplied by my MXML with the correct header, never passed it on to be sent in the request. So I had to tweak the generated code (As well, of course, of adding the "Authorization" header to my WS in the first place). So what I did is:
                                              1. Add the generate the Base64 encoded header:
                                              quote:


                                              public function sendMyWebSerice(event: MouseEvent):void
                                              {
                                              // Get the actual Web service from the generated WSDL class
                                              var ws:BasePromoPlanner=promoPlannerWs.getWebService();
                                              addAuthHeader(ws,usernameField.text,passwordField.text);
                                              .....
                                              ...
                                              ... Send the request etc.
                                              }

                                              // We should have a utility function to add the credentials
                                              private function addAuthHeader(_webservice:*, _username:String, _password:String):void
                                              {
                                              //add the header to service request
                                              var encoder : Base64Encoder = new mx.utils.Base64Encoder();
                                              encoder.encode(_username + ":" + _password);
                                              _webservice.headers["Authorization"] = "Basic " + encoder.toString();
                                              }



                                              Now in open the generated base web service action script generated for you by the Flex Builder. E.g.: If your web service is called "MyMapService", then your base file is called "BaseMyMapService.as". Scroll all the way down to the call function. The signature of the functions is something like:
                                              quote:

                                              private function call(operation:WSDLOperation,args:Object,token:AsyncToken,headers:Array=null):void

                                              Search for the line that has:
                                              quote:

                                              message.url=endpointURI;

                                              After that line add:
                                              quote:


                                              // We are forcing into the message the previously added headers.
                                              message.headers["Authorization"]=this.headers["Authorization"];
                                              message.httpHeaders["Authorization"]=this.headers["Authorization"];



                                              At this point you should be all set. The previous suggestions raised in this thread to user the http://myuser:password@myserviceURL.com/?WSDL are not viable since IE7 will not let you use username and password in the URL citing a security breach.
                                              In my opinion. This is a bug in the Flex Builder generation code (I'm using FB 3.2 Eclipse Plugin), which can be easily fixed (Assuming you have the FB source code ;-) ).
                                              The only issue I still have is to prevent the browser challenge dialog to show up if the credentials we wrong. I'll try to work on that today.
                                              Cheers.
                                              • 21. Re: Basic authentication when calling a web service
                                                snadim
                                                I am trying to access a .net webservice hosted on an IIS server protected by basic authentication. I was trying to do as gkohen has done to import the wsdl in flex builder. But when I enter the wsdl and press next, in the import wsdl wizard, it is bringing up an authentication form asking for username and pasword. When I enter the username and password and press ok, it is not working. It is bringing up the the authentication form again asking for username and password. Due to this, the Flex Builder is not able to auto-generate the code for the web services. It is showing an error "unable to load wsdl". The same wsdl is working with WebService object (without using the import wsdl feature).
                                                It is still bringing up the authentication form but when I enter the credentials manually, it is returning a response. Can anyone suggest a way to get the import wsdl feature working for a webservice protected by basic authentication?
                                                • 22. Re: Basic authentication when calling a web service
                                                  sir_marc

                                                  Awesome work; solved my problem nicely.

                                                  Thanks gkohen!

                                                   

                                                  Cheers,

                                                  Marc.

                                                  • 23. Re: Basic authentication when calling a web service
                                                    winthers

                                                    I�m am trying to convert your solution to be used in flash as a swf that wraps the flex lib swc's, but i am having some difficulties, notting is happening, no errors nothing.

                                                     

                                                    package 
                                                    {
                                                         import flash.display.Sprite;
                                                         import flash.events.Event;
                                                         import mx.rpc.events.FaultEvent;
                                                         import mx.rpc.events.ResultEvent;
                                                         import mx.rpc.http.Operation;
                                                         import mx.rpc.soap.LoadEvent;
                                                         import mx.rpc.soap.WebService;
                                                         import mx.utils.Base64Encoder;
                                                    
                                                         public class Main extends Sprite 
                                                         {
                                                              private var ws:WebService;
                                                              
                                                              public function Main():void {          
                                                                   ws = new WebService();
                                                                   ws.addEventListener(LoadEvent.LOAD, onLoaded);
                                                              }
                                                              
                                                              public function addAuthHeader( userName:String, passWord:String ):void {
                                                                   var encoder:Base64Encoder = new Base64Encoder();
                                                                   encoder.insertNewLines = false;
                                                                   encoder.encode(userName + ":" + passWord);
                                                                   ws.headers["Authorization"] = "Basic " + encoder.toString(); 
                                                              }
                                                              
                                                              public function load( url:String ):void {
                                                                   ws.loadWSDL(url);
                                                              }
                                                              
                                                              private function onLoaded(evt:LoadEvent):void {
                                                                   trace("Loaded:", evt.wsdl);
                                                              }
                                                              
                                                              private function wsdlFault(evt:FaultEvent):void{
                                                                   trace("Fault:", evt.fault);
                                                              }
                                                              
                                                              private function wsdlResult(evt:ResultEvent):void {
                                                                   trace("Resault:", evt.result);
                                                              }
                                                         }
                                                    }
                                                    
                                                    • 24. Re: Basic authentication when calling a web service
                                                      jross101

                                                      I know this is five years later on this forum but there's no solution here or on any other forum.  So after two day's of hammering this out I was able to produce a workable solution.  Create a new user account for testing.

                                                       

                                                      Wu_Xiao's explanation of the issue was dead on.  The WebService does a GET then a POST and for the GET we are unable to supply the Authorization in the header and this is why we get the popup. The POST has the Authorization but it already to late. 

                                                       

                                                      Take these actions

                                                      1 Create a new user on the machine with the web services. Start with a simple name and password (text only)  I had issues with different users. Start clean and simple.

                                                       

                                                      2 Copy your web services a second usable service.  You'll see in my example below i have Ive copied  ServicesSECURE/Services1.asmx?WSDL to ServicesDEFINITION/Services1.asmx?WSDL

                                                       

                                                      3 Remove all of the code inside of your services making the new set of service like a definition service. Make sure all of the inputs and outputs are the same. ServicesDEFINITION will have no coding and empty returns.

                                                      Example  

                                                      [WebMethod]

                                                              public String CountUsers(string group)

                                                              {

                                                                  return "";

                                                              }

                                                      4 Implement the code below. Call the init() right away to instantiate the web service and wait until it loads to use any of the services.  I use a button event to test.

                                                       

                                                      private var testws:WebService = new WebService;

                                                        private function init():void

                                                        {

                                                        testws.wsdl="http://test.com/ServicesDEFINITION/Services1.asmx?WSDL";

                                                        var encoder:Base64Encoder= new Base64Encoder();

                                                        encoder.insertNewLines = false; // see below for why you need to do this

                                                        encoder.encode("USERNAME:PASSWORD");

                                                        testws.httpHeaders = {Authorization:" Basic " + encoder.toString()};

                                                        testws.loadWSDL();

                                                        testws.addEventListener("load", wsdlLoadHandler);

                                                        }

                                                        protected function test_clickHandler(event:MouseEvent):void

                                                        {

                                                        testws["CountUsers"].addEventListener(mx.rpc.events.FaultEvent.FAULT,testFaultHandler);

                                                        testws["CountUsers"].addEventListener(mx.rpc.events.ResultEvent.RESULT,testResultHandler) ;

                                                        testws.endpointURI="http://test.com/ServicesSECURE/Services1.asmx?WSDL";

                                                        testws.getOperation("CountUsers").send("Test");

                                                        }

                                                        protected function wsdlLoadHandler (event:LoadEvent) : void

                                                        {

                                                        //the service has to load before using the getOperation function

                                                        //you could try using mx.core.UIComponent.callLater from

                                                        //this listener and call the gettestws.getOperation("Co....

                                                        }

                                                       

                                                       

                                                      So you'll see that the ServicesDEFINITION (GET) is called and grabs the definition of the Service1 service but this unsecured services is useless because we've removed all of the code.  After the definition GET is called we can change the end point using endpointURI and perform the POST against our secure ServicesSECURE.