Squeazer
Squeazer

Reputation: 1254

BasicHttpBinding security on Windows Phone 8

I have a self-hosted WCF service with simple username / password validation. The "security" part of the code in the conosle app that hosts the service is:

BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
//add endpoint
selfHost.AddServiceEndpoint(typeof(ISettings), b, "SettingsService");

//add creditential check
selfHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
selfHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomValidator();

But i cant figure out what to do on my windows phone to use user / pass creditentials, this is what i have so far:

BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;

sc = new SettingsClient(httpBinding, new EndpointAddress("http://" + addressField.Text + "/IC/SettingsService"));
sc.ClientCredentials.UserName.UserName = "test";
sc.ClientCredentials.UserName.Password = "test123";

This always returns a 401 error. Also i dont have any special configuration in my xml files.

Upvotes: 1

Views: 713

Answers (2)

Stephen Zeng
Stephen Zeng

Reputation: 2818

You can do something like this:

Client config file:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpsBinding_ITestService">
              <security mode="TransportWithMessageCredential" />
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://test/TestService.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpsBinding_ITestService"
            contract="ITestService" name="BasicHttpsBinding_ITestService" />
    </client>
</system.serviceModel>

Client code:

 var client = new TestServiceClient("BasicHttpsBinding_ITestService");
 client.ClientCredentials.UserName.UserName = "User name";
 client.ClientCredentials.UserName.Password = "password";

Upvotes: 1

Squeazer
Squeazer

Reputation: 1254

Ok so i figured this out, i had quite a few problems:

  1. I was runing the self hosted service from another project but i had the App.configfile in the same project as my service. Didnt know it had to be in the same project where you run the service from, stupid of me.

  2. I now have all the configuration in my xml file, but i could probably put it in code and it would still work.

  3. Refer to this LINK, it describes how to do the authentication on WP7 (works well with WP8).

  4. Make sure you update your service reference when you change something in your service.

Client code:

private void Click(object sender, RoutedEventArgs e) {
        ServiceClient sc = new ServiceClient();
        using (OperationContextScope scope = new OperationContextScope(sc.InnerChannel)) {
            HttpRequestMessageProperty request = new HttpRequestMessageProperty();
            request.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " + EncodeBasicAuthenticationCredentials("test", "test123");
            OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, request);
            sc.setPushUriAsync(pushChannel.ChannelUri.ToString());
            }

}

private string EncodeBasicAuthenticationCredentials(string username, string password) {
    string credentials = username + ":" + password;
    var asciiCredentials = (from c in credentials
                            select c <= 0x7f ? (byte)c : (byte)'?').ToArray();

    return Convert.ToBase64String(asciiCredentials);
}

Client config file:

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ISettings" maxBufferSize="2147483647"
                    maxReceivedMessageSize="2147483647">
                    <security mode="TransportCredentialOnly" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://MACHINE_IP_ADDR:8045/MyService/" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_ISettings" contract="SettingsServiceReference.ISettings"
                name="BasicHttpBinding_ISettings" />
        </client>
    </system.serviceModel>
</configuration>

Server config file:

<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ValidatorServiceBehaviour"
               name="WCFServiceLibrary.SettingsService">
        <endpoint binding="basicHttpBinding"
                  bindingConfiguration="ValidatorBinding"
                  contract="WCFServiceLibrary.ISettings"  />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8045/MyService/" />
          </baseAddresses>
        </host>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ValidatorServiceBehaviour">
          <serviceDebug httpsHelpPageEnabled="true"
                        includeExceptionDetailInFaults="true" />
          <serviceMetadata httpGetEnabled="true" />
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
                                    customUserNamePasswordValidatorType="UserValidator.Validator, UserValidator" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <basicHttpBinding>
        <binding name="ValidatorBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>

      </basicHttpBinding>
    </bindings>

  </system.serviceModel>
</configuration>

The Validator is just a standard UserNamePasswordValidator.

Upvotes: 0

Related Questions