I have a WCF Service that requires authentication with a Username/Password credential. My app is an Android app, but I will eventually need to do this on iOS as well. Essentially I just need the client to authenticate with the server for the simple purpose of telling the server who is using the services. The back end requires a username to able to figure out whether the user has access to various things.
I have gone through the painstaking process of setting up these WCF services with BasicHttpsBinding (although https is not required for this scenario), and I am able to authenticate the user. The catch is that it will only authenticate if the user I attempt to log on as is my Windows account name. The problem is that the users of the system are not all Windows Account holders. The usernames and passwords are stored in the database so I need the client to authenticate as a user in the database, not a user on the domain.
My main question is: is this possible? If so, how?
Note: If this were not via Xamarin, I would customBinding and I would use UsernamePasswordAuthentication as I do for other applications. But, it seems to me that Xamarin does not support customBinding.
Here is my server side config so far (probably could be simpler)
<system.web> </system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="standard">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials >
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="Adapt.WCF.CertificateValidator,Adapt.WCF" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpsBinding >
<binding name="standard" closeTimeout="00:02:00" openTimeout="00:02:00" receiveTimeout="00:10:00" sendTimeout="00:02:00" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="true" >
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport" >
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
<services>
<service name="Adapt.WCF.GeneralUtilityService" behaviorConfiguration="standard">
<endpoint binding="basicHttpsBinding" contract="Adapt.WCF.IGeneralUtilityService" bindingConfiguration="standard" />
</service>
</services>
</system.serviceModel>
Here is my client side code:
public static class WCFFactory { #region Static Fields public static GeneralUtilityServiceClient WCFClient; private const string IPAddress = "192.168.1.106"; private const string EndpointAddress = "https://" + IPAddress + "/amsdevservices/generalutilityservice.svc"; private static readonly EndpointAddress _WCFEndPoint = new EndpointAddress(EndpointAddress); private static bool IsServicePointManagerSet = false; #endregion
#region Public Static Methods
/// <summary>
/// Initialises the WCF Client
/// </summary>
public static void InitializeWCFClient()
{
try
{
if (!IsServicePointManagerSet)
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateCertificate);
IsServicePointManagerSet = true;
}
var binding = CreateBasicHttps();
WCFClient = new GeneralUtilityServiceClient(binding, _WCFEndPoint);
WCFClient.ClientCredentials.UserName.UserName = "-";
WCFClient.ClientCredentials.UserName.Password = "-";
}
catch (Exception ex)
{
throw new Exception("InitializeWCFClient", ex);
}
}
/// <summary>
/// Creates Basic HTTP Binding for WCF
/// </summary>
/// <returns></returns>
private static Binding CreateBasicHttps()
{
try
{
var binding = new BasicHttpsBinding
{
//Name = "basicHttpsBinding",
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
TimeSpan timeout = new TimeSpan(0, 5, 0);
binding.SendTimeout = timeout;
binding.OpenTimeout = timeout;
binding.ReceiveTimeout = timeout;
//Can connect with "None" but then there is no authentication
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
return binding;
}
catch (Exception ex)
{
throw new Exception("CreateBasicHttps", ex);
}
}
/// <summary>
/// Dummy callback to tell WCF to accept all certificates
/// </summary>
/// <param name="sender"></param>
/// <param name="cert"></param>
/// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param>
/// <returns></returns>
public static bool ValidateCertificate(object sender, X509Certificate cert,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
#endregion
}
I have also attached a screen shot of my IIS authentication setup.