Error 401 When calling the Sitefinity WCF Web Services

Posted by Community Admin on 04-Aug-2018 09:21

Error 401 When calling the Sitefinity WCF Web Services

All Replies

Posted by Community Admin on 18-Aug-2015 00:00

Hello Sitefinity Team,


I've Started Developing with Sitefinity 8.1 and I need to access to Your WCF Web Services (e.g. ~\Sitefinity\Services\Ecommerce\Catalog\ProductService.svc)

I've tryed to access them like any other Web Service, but I get a 401 error. After searching on the web and Sitefinity Forum I Found a couple of things.


1- I need to Authenticate Before I Use the Services [1& 2]

2- The Claim-Based Authentication is the default Authentication

3- The url used to authenticate is /Sitefinity/Services/Security/Users.svc/authenticate [1 & 2]
4- I also found a snippet provided by Ivan Dimitrov where he codes the authentication Code [3]
5 -Client Api it's worthless to authenticate and allow the request to web services
6- Its needed a STS to Authenticate and it is integrated in my Sitefinity Installation [2]
You may be wondering where this STS is. By default the logic is integrated in your Sitefinity application and can be found under~/Sitefinity/SWT. ” [2]


 After I Read this information I adapted the code provided by Ivan Dimitrov [3] and coded the Call to the ~\Sitefinity\Services\Ecommerce\Catalog\ProductService.svc. And I got 401 error.

'The remote server returned an error: (401) Unauthorized' is a result of wrong credentials, However I tested the same credentials with the Client Api, Through SecurityManager class and I get the “UserLoggingReason.Succes”, so the credentials are Correct.

 

The Strange fact is that I don't have any ~/Sitefinity/SWT folder. May that be the root of my problems?




I'm Using ASP.NET MVC, and I'm doing the request from a Web Api Controller.

And this is the adapted Code:

 

     public static bool AuthenticateRequest(string membershipProvider, string userName, string password, bool rememberMe, ApiController controller)
   

        var jsonData = String.Format(credentialsFormat, membershipProvider, userName, password, rememberMe.ToString().ToLower());
        var credentials = Encoding.UTF8.GetBytes(jsonData);
        string result = InvokeWebMethod(usersServiceUrl, authenticateMethod, "POST", credentials, controller);
        switch (result)
       
            case "0":
                return true;
            default:
                return false;
       

   


    
    public static string InvokeWebMethod(string serviceUrl, string methodName, string httpMethod, byte[] data, ApiController controller)
   

        var request = (HttpWebRequest)WebRequest.Create(String.Concat(sitefinityHost, serviceUrl, methodName));
        request.Method = httpMethod;
        request.ContentType = "application/json";
        request.CookieContainer = new CookieContainer();

        if (cookies != null)
       
            foreach (Cookie cookie in cookies)
                if (!cookie.Expired)
                    request.CookieContainer.Add(cookie);
       

        if (data != null)
       
            request.ContentLength = data.Length;
            using (var writer = request.GetRequestStream())
           
                writer.Write(data, 0, data.Length);
           
       


        using (var response = (HttpWebResponse)request.GetResponse())
       
            cookies = response.Cookies;
            using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
           
                  var cookie = new HttpCookie("customCookie", "cookieVal")
               
                    Expires = DateTime.Now.AddDays(1),
                    Domain = controller.Request.RequestUri.Host,
                    Path = "/"
                ;
                HttpContext.Current.Response.SetCookie(cookie);

                return reader.ReadToEnd();
           



       
   

 

 (I also Changed the sitefinityHost to my machine)









Are all of my 6 premises correct or something have changed?

 What could be the cause of 401?

 

Thank you very much,

 






References :(The Most relevant)


[1] How to Authenticate
(www.sitefinity.com/.../getting_started_with_restful_services_in_sitefinity)

[2] How to Authenticate
(www.sitefinity.com/.../working-with-restful-services-part-2-claims-authentication-and-designing-service-calls)

[3] Authentication Code
(www.sitefinity.com/.../windows-authentication

Posted by Community Admin on 18-Aug-2015 00:00

Hi Again,

When i put the users.svc in the Sitefinity/Public folder I'm Able to Authenticate and I get the 0, 7 or 9 depending if I Succeed Authenticating, Fail Authentication or the user is already logged in. However this is not a solution because of security problems,  but even after get authenticated I could not access to the service.

I Tried the same approach to ProductService.svc but I get This error instead:

 " Telerik.Sitefinity was not granted ManageEcommerce in Backend for principals with IDs 00000000-0000-0000-0000-000000000000" 

 

I read that Sitefinity/Services requires Administrator Role and Sitefinity/Public is for General Users. The strange thing here is that Test user is Admin and Backend user and can't access to a service in either

 ~\Sitefinity\Services\Ecommerce\Catalog\ProductService.svc

or

~\Sitefinity\Public\ProductService.svc

 

What could be Wrong?

 

 

Posted by Community Admin on 21-Aug-2015 00:00

Hi Nelson,

You are correct in that you need to authenticate if you want to use the services under /sitefinity, including (/sitefinity/services). All routes that are under /sitefinity require backend user authentication. Some of them also require to have permissions over the content that you want to manage - this is why you might get Telerik.Sitefinity was not granted ManageEcommerce even if authenticated.
It depends from where you will authenticate and whether you can persist the cookies that will be sent with the response once you have authenticated and have accessed protected resource:

private static HttpStatusCode SignOut(NameValueCollection requestHeaders)
        
            WebRequest wrGETURLSignOut = WebRequest.Create("http://localhost/Sitefinity/SignOut"); // pass the url as parameter or set it outside
            wrGETURLSignOut.Headers.Add(requestHeaders);
            var resp = wrGETURLSignOut.GetResponse();
            var code = ((System.Net.HttpWebResponse)(resp)).StatusCode;
            return code;
        
 
        private static NameValueCollection SignIn(string username, string password)
        
            string sURL;
            sURL = "http://localhost/Sitefinity/Authenticate/SWT"; // pass the url as parameter or set it outside
 
            var formData = String.Format("wrap_name=0&wrap_password=1", username, password);
            var bytes = Encoding.UTF8.GetBytes(formData);
 
            WebRequest wrGETURL;
            wrGETURL = WebRequest.Create(sURL);
            wrGETURL.Method = "POST";
            wrGETURL.ContentType = "application/x-www-form-urlencoded";
            wrGETURL.ContentLength = bytes.Length;
            Stream dataStream = wrGETURL.GetRequestStream();
            dataStream.Write(bytes, 0, bytes.Length);
            dataStream.Close();
 
            Stream objStream = wrGETURL.GetResponse().GetResponseStream();
 
            StreamReader objReader = new StreamReader(objStream);
            var token = objReader.ReadToEnd();
 
            var nameValueColl = HttpUtility.ParseQueryString(token);
            var bootstrapToken = nameValueColl["wrap_access_token"];
            var expiresOn = DateTime.Now + TimeSpan.FromSeconds(int.Parse(nameValueColl["wrap_access_token_expires_in"]));
 
            var requestHeaders = new NameValueCollection();
            requestHeaders["Authorization"] = String.Format("WRAP access_token=\"0\"", bootstrapToken);
            return requestHeaders;
        

The above can be called from even a console application. Note that you might get also 'User already logged in' in this case you should log out and then login again:
            var testUrl = "http://localhost/sitefinity/pages";
            var requestHeaders = SignIn("admin", "password");
 
            WebRequest protectedRequest = CreateRequest(testUrl, requestHeaders);
 
            WebResponse response = null;
            try
            
                response = protectedRequest.GetResponse();
            
            catch (WebException ex)
            
                if (ex.Status == WebExceptionStatus.ProtocolError)
                
                    var statusCode = SignOut(requestHeaders);
                    if (statusCode == HttpStatusCode.OK)
                    
                        var newRequestHeaders = SignIn("admin", "password");
                        requestHeaders = newRequestHeaders;
                        WebRequest protectedRequest2 = CreateRequest(testUrl, newRequestHeaders);
 
                        response = protectedRequest2.GetResponse();
                    
                
            
 
            //process response
...
            // call other service /or same again
            WebRequest protectedRequest3 = CreateRequest(testUrl, requestHeaders);
            var response3 = protectedRequest3.GetResponse();
              //process response
...
 
            SignOut(requestHeaders);
        
 
        public static WebRequest CreateRequest(string url, NameValueCollection requestHeaders)
        
            WebRequest wrGETURLProtected2 = WebRequest.Create(url);
            wrGETURLProtected2.ContentType = "application/json";
            wrGETURLProtected2.Headers.Add(requestHeaders);
            return wrGETURLProtected2;
        


Regards,
Nikola Zagorchev
Telerik
 
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Sitefinity CMS Ideas&Feedback Portal and vote to affect the priority of the items
 

This thread is closed