Archive

Archive for the ‘C#’ Category

Modifying SOAP Header WCF.

October 9, 2015 Leave a comment

While Working on a project , I had a requirement to communicate with a service hosted in non Microsoft environment, so the service did not like the way SOAP security header was being sent it.

SO I had to modify the SOAP security header , wow..

it was really pain in my neck , ha ha ha.. so modify it.

following steps helped me to modify it.

1) Change the binding to custom binding.

<customBinding>
<binding name="CustomSoapBinding">
<security includeTimestamp="false" authenticationMode="UserNameOverTransport" defaultAlgorithmSuite="Basic256" requireDerivedKeys="false" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
<textMessageEncoding messageVersion="Soap11"/>
<httpsTransport maxReceivedMessageSize="2000000000"/>
</binding>
</customBinding>

 

Things to note, Service did not like the timestamp in security header , so I had to exclude it, also note below joke..

messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"

ohh..what on the earth does that mean…ha ha ha.try to remember it.. Smile

2)  before calling the service , make the changes.

   1: ws.ChannelFactory.Endpoint.Behaviors.Remove<System.ServiceModel.Description.ClientCredentials>();

   2: ws.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentials());

   3: ws.ClientCredentials.UserName.UserName = ConfigReader.GetConstantValue("UserID");

   4: ws.ClientCredentials.UserName.Password = ConfigReader.GetConstantValue("Password");

   5:                

things to note

Line 1 :  removes the Client Credentials node from SOAP Security header.

Line 2 : Added a class[which we will see in a bit, which performs all the actions which are required to build custom security header node ].

Line 3, Line 4 : added some custom credentials.

3)  Custom Credential Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Description;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Text;
using System.Security.Cryptography;
using System.IdentityModel.Tokens;

namespace MedImpactServicesClient
{
public class CustomCredentials : ClientCredentials
{
public CustomCredentials()
{ }

protected CustomCredentials(CustomCredentials cc)
: base(cc)
{ }

public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager()
{
return new CustomSecurityTokenManager(this);
}

protected override ClientCredentials CloneCore()
{
return new CustomCredentials(this);
}
}

public class CustomSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
public CustomSecurityTokenManager(CustomCredentials cred)
: base(cred)
{ }

public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version)
{
return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity11);
}
}

public class CustomTokenSerializer : WSSecurityTokenSerializer
{
public CustomTokenSerializer(SecurityVersion sv)
: base(sv)
{ }

protected override void WriteTokenCore(System.Xml.XmlWriter writer,
System.IdentityModel.Tokens.SecurityToken token)
{


UserNameSecurityToken userToken = token as UserNameSecurityToken;


string tokennamespace = "o";

DateTime created = DateTime.UtcNow;
string createdStr = created.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");

// unique Nonce value - encode with SHA-1 for 'randomness'
// in theory the nonce could just be the GUID by itself
//string phrase = Guid.NewGuid().ToString();
byte[] nonce = GetNonce();
string nonceStr = Convert.ToBase64String(nonce);

// in this case password is plain text
// for digest mode password needs to be encoded as:
//string PasswordAsDigest = GetSHA1String(userToken.Password);
// and profile needs to change to
string password = CreateHashedPassword(nonce, createdStr, userToken.Password);

//string password = userToken.Password;

writer.WriteRaw(string.Format(
"<{0}:UsernameToken u:Id=\"" + token.Id +
"\" xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
"<{0}:Username>" + "WSPAHUM" + "</{0}:Username>" +
"<{0}:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" +
password + "</{0}:Password>" +
"<{0}:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" +
nonceStr + "</{0}:Nonce>" +
"<u:Created>" + createdStr + "</u:Created></{0}:UsernameToken>", tokennamespace));
}

private string CreateHashedPassword(byte[] nonce, string created, string password)
{
byte[] createdBytes = Encoding.UTF8.GetBytes(created);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] combined = new byte[createdBytes.Length + nonce.Length + passwordBytes.Length];
Buffer.BlockCopy(nonce, 0, combined, 0, nonce.Length);
Buffer.BlockCopy(createdBytes, 0, combined, nonce.Length, createdBytes.Length);
Buffer.BlockCopy(passwordBytes, 0, combined, nonce.Length + createdBytes.Length, passwordBytes.Length);
return Convert.ToBase64String(SHA1.Create().ComputeHash(combined));
}

internal static byte[] GetNonce()
{
byte[] nonce = new byte[0x10];
RandomNumberGenerator generator = new RNGCryptoServiceProvider();
generator.GetBytes(nonce);
return nonce;
}





}
}

 

Things to Note:

Most of the work is done in WriteTokenCore function and just copy everything related to Nounce, it took me around 1 week to figure out correct CreateHashedPassword algo.Smile

 

That’s it you are done.

let me know if you get stuck somewhere.

Advertisements
Categories: C#, WCF Tags: , ,

Launching WCF Test client From Service Application.

October 9, 2015 Leave a comment

When we create a WCF Service Application , and when we try to debug service application you will find that sometimes it launches browser instead of WCF test client.

its very easy to fix this problem.

open you solution and right click on the SVC file and set it as a start page.

image

 

then run the project you will be happy to see your test client.

image

 

Happy weekend.. Smile

Storing Multiple Values in Dictionary C#

October 9, 2015 Leave a comment

We All know the famous Dictionary

Dictionary<string,string> myDictionary

Its normally used for storing Key, Value pair.

Sometimes we want to store something like Key,Value,value.

for eg.

Dictionary<string,string,string> myDictionary

Unfortunately we don’t such structure in .Net, but there is workaround for such situation.

Create a Class or Struct and use it as Value.

for eg.

public class MyClass
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}

Dictionary<string, MyClass> myDictionary

 

Hope this helps.

Categories: C#, Tips Tags: , ,