Authenticating to Java web services with C# using SOAP authentication
Download ProjectWell, we did method 1, basic authentication in our last post: Authenticating to Java web services with C# using basic authentication (using FlexNet services as examples). Let’s do method 2 here.
Method 2 – SOAP Authentication
SOAP authentication is a bit tricky. We have to get to the SOAP request and add headers but we don’t have access to the SOAP header through our SOAP service clients. Once we have access, we need to create custom SoapHeader objects.
We have to use a SoapExtension. A SoapExtension will apply to all SAOP requests, and we may not want that, so we need to enable it based on service.
Step 1 – Create Custom SOAP Header objects for UserId and UserPassword
I created a base object. Notice the XmlText attribute.
using System.Web.Services.Protocols; using System.Xml.Serialization; namespace ConnectToFlexeraExample.Model { public class BaseSoapHeader : SoapHeader { public BaseSoapHeader() { Actor = "http://schemas.xmlsoap.org/soap/actor/next"; MustUnderstand = false; } [XmlText] public virtual string Value { get; set; } } }
Then a UserIdSoapHeader object. Notice the XmlRoot attribute.
using System.Xml.Serialization; namespace ConnectToFlexeraExample.Model { [XmlRoot("UserId", Namespace = "urn:com.macrovision:flexnet/platform")] public class UserIdSoapHeader : BaseSoapHeader { } }
using System; using System.Text; using System.Xml.Serialization; namespace ConnectToFlexeraExample.Model { [XmlRoot("UserPassword", Namespace = "urn:com.macrovision:flexnet/platform")] public class PasswordSoapHeader : BaseSoapHeader { [XmlIgnore] public string EncodedPassword { set { Value = Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); } } } }
Step 2 – Add a SoapHeaderInjectionExtension : SoapExtension
using ConnectToFlexeraExample.Model; using System; using System.Collections.Generic; using System.Net; using System.Web.Services.Protocols; namespace ConnectToFlexeraExample.Extensions { public class SoapHeaderInjectionExtension : SoapExtension { public static Dictionary<string, bool> EnabledServices = new Dictionary<string, bool>(); public static Dictionary<string, NetworkCredential> UserAndPassword = new Dictionary<string, NetworkCredential>(); public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute) { return null; // Unused } public override object GetInitializer(Type serviceType) { return null; // Unused } public override void Initialize(object initializer) { // Unused } public override void ProcessMessage(SoapMessage message) { if (!IsEnabledForUrl(message.Url)) return; switch (message.Stage) { case SoapMessageStage.BeforeSerialize: NetworkCredential creds; if (UserAndPassword.TryGetValue(message.Url, out creds)) { message.Headers.Add(new UserIdSoapHeader { Value = creds.UserName }); message.Headers.Add(new PasswordSoapHeader { EncodedPassword = creds.Password }); } break; case SoapMessageStage.AfterSerialize: break; case SoapMessageStage.BeforeDeserialize: break; case SoapMessageStage.AfterDeserialize: break; } } public bool IsEnabledForUrl(string url) { bool isEnabled; EnabledServices.TryGetValue(url, out isEnabled); return isEnabled; } } }
Step 3 – Add the SoapExtension to the .config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- Other stuff --> <system.web> <webServices> <soapExtensionTypes> <add type="ConnectToFlexeraExample.Extensions.SoapHeaderInjectionExtension, ConnectToFlexeraExample" priority="1" group="High" /> <add type="ConnectToFlexeraExample.Extensions.SoapLoggerExtension, ConnectToFlexeraExample" priority="2" group="Low" /> </soapExtensionTypes> </webServices> </system.web> </configuration>
Step 4 – Update SetNetworkCredentials extension method
We now want this method to accept either SOAP or Basic auth. We are going to key off of PreAuthenticate.
public static class WebClientProtocolExtensions { public static void SetNetworkCredentials(this WebClientProtocol client, string username, string password, string customUrl = null, bool preAuthenticate = true) { client.PreAuthenticate = preAuthenticate; client.Url = string.IsNullOrWhiteSpace(customUrl) ? client.Url : customUrl; var netCredential = new NetworkCredential(username, password); if (preAuthenticate) { ICredentials credentials = netCredential.GetCredential(new Uri(client.Url), "Basic"); client.Credentials = credentials; } else { SoapHeaderInjectionExtension.EnabledServices[client.Url] = true; SoapHeaderInjectionExtension.UserAndPassword[client.Url] = netCredential; } } }
Step 5 – Use the new service clients with SOAP
private static void TestAuthenticationService(string user, string pass) { // Basic Auth Method // authenticationServiceClient.SetNetworkCredentials(user, pass); // Soap Auth Method authenticationServiceClient.SetNetworkCredentials(user, pass, null, false); var userInputType = new AuthenticateUserInputType { userName = user, password = pass, domainName = "FLEXnet" }; var result = authenticationServiceClient.authenticateUser(userInputType); Logger.Info(result.Success); }
And you are autenticating to Flexera SOAP-based java web services using C#!