Search code examples
restwcfbasic-authentication

Authorization header in ServiceAuthorizationManager is null in second call


I have a WCF REST service which accepts xml data as input and returns some data too. To implement Basic Authentication i use ServiceAuthorizationManager. The CheckAccessCore method calls twice automatically. In first call authorization header in CheckAccessCore is correct, but in second call authorization header is null.

ServiceAuthorizationManager CheckAccessCore method

protected override bool CheckAccessCore(OperationContext operationContext)
    {
        var authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];

        if (!string.IsNullOrEmpty(authHeader))
        {
            var credentials = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(authHeader.Substring(6))).Split(':');
            var user = new
            {
                Name = credentials[0],
                Password = credentials[1]
            };

            if (user.Name == "test" && user.Password == "pass")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm =\"CreditData\"");
            throw new WebFaultException(HttpStatusCode.Unauthorized);
        }
    }

WCF Web.config

<system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="RestBehavior">
          <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Xml"/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceAuthorization serviceAuthorizationManagerType="CreditDataService.Authorization.CreditDataAuthorizationManager, CreditDataService" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="CreditDataService.Services.CreditData" behaviorConfiguration="">
        <endpoint name="REST" behaviorConfiguration="RestBehavior" binding="webHttpBinding" contract="CreditDataService.Contracts.ICreditData"/>
      </service>
    </services>
    <protocolMapping>
      <add binding="webHttpBinding" scheme="https"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>

Client

private void button4_Click(object sender, EventArgs e)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:33016/Services/CreditData.svc");
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes("<Request><Firstname>John</Firstname><Lastname>Doe</Lastname><Pid>123456789</Pid></Request>");
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = bytes.Length;
            request.Method = "POST";

            string credentials = "test:pass";
            string enc = Convert.ToBase64String(Encoding.ASCII.GetBytes(credentials));
            string auth = string.Format("{0} {1}", "Basic", enc);

            request.Headers[HttpRequestHeader.Authorization] = auth;

            Stream reqStream = request.GetRequestStream();
            reqStream.Write(bytes, 0, bytes.Length);
            reqStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream respStream = response.GetResponseStream();
                string respStr = new StreamReader(respStream).ReadToEnd();
                MessageBox.Show(respStr);
            }
        }
        catch (WebException ex)
        {
            if (ex.Response != null)
            {
                var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
                MessageBox.Show(resp);
            }

            MessageBox.Show(ex.Message);
        }
    }

Without ServiceAuthorizationManager it works correctly.


Solution

  • Problem was webservice's method's UriTemplate. It was empty and when i was calling service there was happening redirecting to the same url only with slash. e.g. when i sent request to "http://localhost/myservice.svc" it was redirected to "http://localhost/myservice.svc/". This arose second request and exactly this second request had Authorization header null. When i added UriTemplate problem solved.