#define TRACE using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.ServiceModel.Security; using System.ServiceModel.Security.Tokens; using System.Xml; using ArchestrAServices.Common; namespace ArchestrAServices.Contract; public class TokenManager { public static UserToken RepackageSamlToken(UserToken userAuthentication, byte[] incomingSharedSecret, byte[] outgoingSharedSecret) { SamlSecurityToken samlReadToken = ExtractIncomingSamlToken(userAuthentication, incomingSharedSecret); string tokenId = string.Empty; return SerializeSamlToken(PackageOutgoingSamlToken(samlReadToken, outgoingSharedSecret, out tokenId), tokenId); } public static SamlSecurityToken ExtractIncomingSamlToken(UserToken userAuthentication, byte[] incomingSharedSecret) { if (incomingSharedSecret == null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "ExtractIncomingSamlToken: incomingSharedSecret cannot be null"); return null; } SamlSecurityToken samlSecurityToken = null; try { SecurityToken item = new BinarySecretSecurityToken(userAuthentication.Password, incomingSharedSecret); WSSecurityTokenSerializer wSSecurityTokenSerializer = new WSSecurityTokenSerializer(SecurityVersion.WSSecurity11, emitBspRequiredAttributes: false, new SamlSerializer()); XmlReader reader = XmlReader.Create(new MemoryStream(userAuthentication.SamlToken)); if (wSSecurityTokenSerializer.CanReadToken(reader)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Serializer is capable of reading SAML token from XML"); SecurityTokenResolver tokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(new List { item }.AsReadOnly(), canMatchLocalId: true); SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Serializer is reading token"); SecurityToken securityToken = wSSecurityTokenSerializer.ReadToken(reader, tokenResolver); if (securityToken != null) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Serializer successfully read a token"); samlSecurityToken = securityToken as SamlSecurityToken; if (samlSecurityToken == null) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Serializer could not read a SAML token"); } } else { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Serializer could not read the token"); } } else { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "Serializer is NOT capable of reading SAML token to XML"); } } catch (Exception ex) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, string.Format(CultureInfo.CurrentCulture, "Exception deserializing SAML token: {0}", new object[1] { ex.Message })); Exception innerException = ex.InnerException; if (innerException != null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, string.Format(CultureInfo.CurrentCulture, "--> {0}", new object[1] { innerException.Message })); Exception innerException2 = innerException.InnerException; if (innerException2 != null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, string.Format(CultureInfo.CurrentCulture, "--> {0}", new object[1] { innerException2.Message })); } } } return samlSecurityToken; } private static SamlSecurityToken PackageOutgoingSamlToken(SamlSecurityToken samlReadToken, byte[] outgoingSharedSecret, out string tokenId) { tokenId = string.Empty; if (samlReadToken == null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "PackageOutgoingSamlToken: samlReadToken cannot be null"); return null; } if (outgoingSharedSecret == null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, "PackageOutgoingSamlToken: outgoingSharedSecret cannot be null"); return null; } SamlSecurityToken result = null; try { SecurityToken securityToken = new BinarySecretSecurityToken(outgoingSharedSecret); tokenId = securityToken.Id; SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, string.Format(CultureInfo.CurrentCulture, "PackageOutgoingSamlToken: creating skic from id='{0}'", new object[1] { securityToken.Id })); SecurityKeyIdentifierClause securityKeyIdentifierClause = securityToken.CreateKeyIdentifierClause(); SecurityKeyIdentifier signingKeyIdentifier = new SecurityKeyIdentifier(securityKeyIdentifierClause); List list = new List(1); SecurityKeyIdentifier securityKeyIdentifier = null; list.Add(SamlConstants.SenderVouches); new SamlSubject(null, null, null, list, null, securityKeyIdentifier); SigningCredentials signingCredentials = new SigningCredentials(securityToken.SecurityKeys[0], "http://www.w3.org/2000/09/xmldsig#hmac-sha1", "http://www.w3.org/2000/09/xmldsig#sha1", signingKeyIdentifier); SamlAssertion assertion = samlReadToken.Assertion; result = new SamlSecurityToken(new SamlAssertion(assertion.AssertionId, assertion.Issuer, assertion.IssueInstant, assertion.Conditions, assertion.Advice, assertion.Statements) { SigningCredentials = signingCredentials }); } catch (Exception ex) { SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, string.Format(CultureInfo.CurrentCulture, "Exception caught in CreateSamlToken: '{0}'", new object[1] { ex.Message })); } return result; } public static UserToken SerializeSamlToken(SamlSecurityToken samlToken, string tokenId) { UserToken result = default(UserToken); if (samlToken != null) { WSSecurityTokenSerializer wSSecurityTokenSerializer = new WSSecurityTokenSerializer(SecurityVersion.WSSecurity11, emitBspRequiredAttributes: true, new SamlSerializer()); if (wSSecurityTokenSerializer.CanWriteToken(samlToken)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Verbose, 0, "Serializer is capable of writing SAML token to XML"); try { using (MemoryStream memoryStream = new MemoryStream()) { XmlWriter writer = XmlWriter.Create(memoryStream); wSSecurityTokenSerializer.WriteToken(writer, samlToken); result.IdType = EnumASBFactory.CredentialTypeToInt(CredentialType.SamlToken); result.SamlToken = memoryStream.ToArray(); result.Password = tokenId; } SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Verbose, 0, string.Format(CultureInfo.CurrentCulture, "Serialized SAML Token {0}:", new object[1] { samlToken.Id })); } catch (Exception ex) { SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, string.Format(CultureInfo.CurrentCulture, "Exception during serialization: '{0}'", new object[1] { ex.Message })); Exception innerException = ex.InnerException; if (innerException != null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, string.Format(CultureInfo.CurrentCulture, "-> '{0}'", new object[1] { innerException.Message })); Exception innerException2 = innerException.InnerException; if (innerException2 != null) { SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, string.Format(CultureInfo.CurrentCulture, "-> '{0}'", new object[1] { innerException2.Message })); } } } } else { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Verbose, 0, "Serializer is NOT capable of writing SAML token to XML"); } } return result; } }