How to Pass a Username/Password in the Header to a Soap Wcf Service

How can I pass a username/password in the header to a SOAP WCF Service

There is probably a smarter way, but you can add the headers manually like this:

var client = new IdentityProofingService.IdentityProofingWSClient();

using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
new SecurityHeader("UsernameToken-49", "12345/userID", "password123"));
client.invokeIdentityService(new IdentityProofingRequest());
}

Here, SecurityHeader is a custom implemented class, which needs a few other classes since I chose to use attributes to configure the XML serialization:

public class SecurityHeader : MessageHeader
{
private readonly UsernameToken _usernameToken;

public SecurityHeader(string id, string username, string password)
{
_usernameToken = new UsernameToken(id, username, password);
}

public override string Name
{
get { return "Security"; }
}

public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}

protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
serializer.Serialize(writer, _usernameToken);
}
}

[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
public UsernameToken()
{
}

public UsernameToken(string id, string username, string password)
{
Id = id;
Username = username;
Password = new Password() {Value = password};
}

[XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id { get; set; }

[XmlElement]
public string Username { get; set; }

[XmlElement]
public Password Password { get; set; }
}

public class Password
{
public Password()
{
Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
}

[XmlAttribute]
public string Type { get; set; }

[XmlText]
public string Value { get; set; }
}

I have not added the Nonce bit to the UsernameToken XML, but it is very similar to the Password one. The Created element also needs to be added still, but it's a simple [XmlElement].

WCF Username and Password in SOAP Header

Use this binding:

<customBinding>
<binding name="NewBinding0">
<textMessageEncoding messageVersion="Soap12" />
<security authenticationMode="UserNameOverTransport">
<secureConversationBootstrap />
</security>
<httpsTransport />
</binding>
</customBinding>

Of course you also need to supply user/pass on the proxy:

proxy.ClientCredentials.Username.Username = "user"
proxy.ClientCredentials.Username.Password = "pass"

All this assumes you also use SSL. If you don't then check out CUB.

How to pass Header for the WCF SOAP Service

The scope of the OperationContxtScope is only available within Using statement, namely, the service request with the specific soap header is valid in the Using statement. the other call is restored outside of the Using statement, without a specifical header.

We can use the IClientMessageInspector interface if we want to permanently add message headers to every requests.

https://putridparrot.com/blog/adding-data-to-wcf-message-headers-client-side

Please refer to my previous reply.

Adding an outgoing message headers in WCF can't be retrieved in incoming message headers

Feel free to let me know if there is anything I can help with.

Authentication of external requests - how to pass user credentials in the SOAP header?

You should pass it the credential from the credential cache like so:

client.Credentials = System.Net.CredentialCache.DefaultCredentials;

or give it explicitly:

client.Credentials = new System.Net.NetworkCredential("username", "password");

Also I like to use client.PreAuthenticate = true;, but there may be issues around that, that I'm ignoring.

WCF Soap Header with PasswordText

Here's what I did to get it to work:

            CustomBinding binding = new CustomBinding();

binding.Name = "ClearUsernameBinding_IUserDetailsService";

binding.SendTimeout = TimeSpan.FromMinutes(2);
binding.OpenTimeout = TimeSpan.FromMinutes(2);
binding.CloseTimeout = TimeSpan.FromMinutes(2);
binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8));
binding.Elements.Add(TransportSecurityBindingElement.CreateUserNameOverTransportBindingElement());
binding.Elements.Add(new HttpsTransportBindingElement());

EndpointAddress endpoint = new EndpointAddress(new Uri("https://MYURL"));
ServiceReference1.UserDetailsServiceClient proxy = new ServiceReference1.UserDetailsServiceClient(binding, endpoint);

proxy.Endpoint.Contract.Name = "IScheduledVisitsService";
proxy.Endpoint.Contract.ConfigurationName = "ClearUsernameBinding_IScheduledVisitsService";
proxy.Endpoint.Address = endpoint;
proxy.Endpoint.Binding = binding;
proxy.ClientCredentials.UserName.UserName = Loginmodel.UserName;
proxy.ClientCredentials.UserName.Password = Loginmodel.Password;
UserDTO result = await proxy.GetUserByUsernameAsync(Loginmodel.UserName);

Which is the equivalent of the following if done in config

    <binding name="myBinding">
<security defaultAlgorithmSuite="Default" authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
includeTimestamp="true"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
</security>
<textMessageEncoding messageVersion="Soap11" />
</binding>`

But like SuMMeR said, this will only work with HTTPS. If you want to allow for insecure, you can add the allowInsecureTransport="true" to the <security> element in the config file. If you want to do it in code, I think you could just try something like:

TransportSecurityBindingElement mySecElement = new TransportSecurityBindingElement {  AllowInsecureTransport = true };
binding.Elements.Add(mySecElement);

How can I pass a Soap Header to a SOAP WCF Service in Visual Studio?

First, need add web service "https://92.46.122.150:8443/esf-web/ws/SessionService?wsdl" like Service Reference.

Second, your certificate should be like trusted. If not, then you can do this using code below:

System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Third, add in your solution new item like C# class for your SOAP header. In this class shoud be code like below:

namespace WindowsFormsApplication1
{
public class MySoapSecurityHeader : MessageHeader
{
private readonly UsernameToken _usernameToken;

public MySoapSecurityHeader(string username, string password)
{
_usernameToken = new UsernameToken(string.Empty, username, password);
}

public MySoapSecurityHeader(string id, string username, string password)
{
_usernameToken = new UsernameToken(id, username, password);
}

public override string Name
{
get { return "Security"; }
}

public override string Namespace
{
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}

protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
serializer.Serialize(writer, _usernameToken);
}
}

[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
public UsernameToken()
{
}

public UsernameToken(string id, string username, string password)
{
Id = id;
Username = username;
Password = new Password() { Value = password };
}

[XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id { get; set; }

[XmlElement]
public string Username { get; set; }

[XmlElement]
public Password Password { get; set; }
}

public class Password
{
public Password()
{
Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
}

[XmlAttribute]
public string Type { get; set; }

[XmlText]
public string Value { get; set; }
}
}

After that you need add code in a file "Form1.cs":

//The path to the certificate.
string certPath = "C:/AUTH_RSA256_e9f5afab50193175883774ec07bac05cb8c9e2d7.p12";

//Password to signing a certificate
string certPassword = "123456";

//IIN or BIN persom who signing ESF on esf_gov site
var tin = "123456789021";

//Load the certificate into an X509Certificate object.
X509Certificate x509Cert = new X509Certificate(certPath, certPassword);

//Transfer sertificate to string value of base64
var certPEM = ExportToPEM(x509Cert);

using (SessionServiceClient client = new SessionServiceClient())
{
using (new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
new MySoapSecurityHeader("123456789011", "TestPass123"));

//Create session for a work with site ESF
CreateSessionRequest createSessionRequest = new CreateSessionRequest
{
tin = tin,
x509Certificate = certPEM
};

var response = client.createSession(createSessionRequest);
MessageBox.Show("Session ID is: " + response.sessionId, "Information message",
MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);

//Close session for a work with site ESF
CloseSessionRequest closeSessionRequest = new CloseSessionRequest
{
sessionId = response.sessionId,
tin = tin,
x509Certificate = certPEM
};

var closeResponse = client.closeSession(closeSessionRequest);
}
}

}
public static string ExportToPEM(X509Certificate cert)
{
//Export certificate, get baty array, convert in base64 string
return Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks);
}

Then run a programm and this will be work.

How to pass credentials to a SOAP webservice?

You'll need to set the credentials on the client, like as shown in this MSDN article:

client.ClientCredentials.UserName.UserName = "my_user_name";
client.ClientCredentials.UserName.Password = "my_password";

WCF client configuration for 3rd party SOAP 1.1 service with plain text username credentials over SSL

It just so happens Rick Strahl had the same problem. Here's the link to his blog post describing and solving the problem.

Issue:

The issue is that WCF expects a TimeStamp Soap header in the response.
If you look at the outbound response and the Soap headers you'll see
that there's a timestamp there. The timestamp is expected to be
returned on the return Soap response. Note that this is not a
requirement of WS-Security so WCF is doing something 'special' here
that is in effect breaking this service call.

Solution:

BindingElementCollection elements = client.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = false;
client.Endpoint.Binding = new CustomBinding(elements);

The above code modifies the Binding configuration by explicitly
removing the Timestamp from the outbound call which removes the
requirement for the server to return it. And this makes WCF happy and
the call goes through.



Related Topics



Leave a reply



Submit