WCF: Añadiendo Nonce a UsernameToken

Intento conectarme a un servicio web, escrito en Java, pero hay algo que no puedo entender.

Usando WCF y un CustomBinding, casi todo parece estar bien, excepto una parte del mensaje SOAP, ya que le faltan los nodos de pieza Nonce y Created. Obviamente me falta algo, así que si pudieras dirigirme en la dirección correcta, sería muy apreciado.

Aquí está el enlace personalizado:

      

Y aquí está la parte relevante del mensaje:

           

Y así es como debería verse:

   .. .. 6ApOnLn5Aq9KSH46pzzcZA== 2009-05-13T18:59:23.309Z   

Entonces la pregunta es: ¿cómo podría introducir los elementos Nonce y Created dentro de la parte de seguridad?

Para crear el nonce, tuve que cambiar algunas cosas

Primero, agregué un enlace personalizado en mi configuración

                

Luego, tome este código que se encuentra aquí: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/4df3354f-0627-42d9-b5fb-6e880b60f8ee y modifíquelo para crear el nonce (solo un al azar hash, codificado en base 64)

 protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token) { Random r = new Random(); string tokennamespace = "o"; DateTime created = DateTime.Now; string createdStr = created.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); string nonce = Convert.ToBase64String(Encoding.ASCII.GetBytes(SHA1Encrypt(created + r.Next().ToString()))); System.IdentityModel.Tokens.UserNameSecurityToken unToken = (System.IdentityModel.Tokens.UserNameSecurityToken)token; 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>" + unToken.UserName + "" + "< {0}:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">" + unToken.Password + "" + "< {0}:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "" + "" + createdStr + "", tokennamespace)); } protected String ByteArrayToString(byte[] inputArray) { StringBuilder output = new StringBuilder(""); for (int i = 0; i < inputArray.Length; i++) { output.Append(inputArray[i].ToString("X2")); } return output.ToString(); } protected String SHA1Encrypt(String phrase) { UTF8Encoding encoder = new UTF8Encoding(); SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider(); byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase)); return ByteArrayToString(hashedDataBytes); } 

Yo tuve el mismo problema. En lugar del serializador de token personalizado utilicé un MessageInspector para agregar el UsernameToken correcto en el método BeforeSendRequest . Luego utilicé un comportamiento personalizado para aplicar la corrección.

Todo el proceso está documentado (con un proyecto de demostración ) en la publicación de mi blog Admitiendo el Resumen de contraseña de perfil básico de WS-I en un proxy de cliente WCF . Alternativamente, puedes leer el PDF .

Si desea seguir mi progreso hasta llegar a la solución, la encontrará en StackOverflow titulada ” Error en el cliente WCF que consume el servicio web Axis 2 con WS-Security UsernameToken PasswordDigest authentication scheme “:

Este artículo proporciona ejemplos con la integración completa de UserNameToken Profile con la contraseña digerida en la interconexión de seguridad de WCF.

Vale la pena señalar que Rick Strahl hizo una publicación de blog (que hace referencia a esta pregunta) donde explica todo con bastante claridad y ofrece soluciones tanto para Password como para PasswordDigest.

Publico esto porque encontré este artículo originalmente, no pude seguirlo, y encontré la publicación de Rick mucho más tarde. Esto podría salvar a algunas personas en algún momento.

WCF WSSecurity y WSE Nonce Autenticación

También tuve que poner un segmento UserNameHeader en el encabezado del mensaje SOAP:

    foouser foopass       

Esto se logró con un encabezado de mensaje personalizado:

 public class UserNamePasswordHeader : MessageHeader { private readonly string _serviceUserEmail; private readonly string _serviceUserPassword; public UserNamePasswordHeader(string serviceUserEmail, string serviceUserPassword) { this._serviceUserEmail = serviceUserEmail; this._serviceUserPassword = serviceUserPassword; } public override string Name { get { return "UserNameHeader"; } } public override string Namespace { get { return "urn:bar:services"; } } protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) { writer.WriteElementString("UserName", _serviceUserEmail); writer.WriteElementString("Password", _serviceUserPassword); } } 

Otras tags, como Nonce y Created , podrían agregarse fácilmente.

La clase se usa de la siguiente manera:

 var service = new BarServiceClient(); service.ClientCredentials.ClientCertificate.Certificate = MessageSigningCertificate; using (new OperationContextScope(service.InnerChannel)) { OperationContext.Current.OutgoingMessageHeaders.Add( new UserNamePasswordHeader(serviceUserEmail, serviceUserPassword)); try { var response = service.GetUserList(); return response; } finally { service.Close(); } } 

Nota: MessageSigningCertificate es un certificado X.509, lo leí desde un archivo:

 private static X509Certificate2 LoadCertificateFromFile(string pfxFilePath, string privateKeyPassword) { // Load the certificate from a file, specifying the password var certificate = new X509Certificate2(pfxFilePath, privateKeyPassword); return certificate; }