public static LinkIDAuthnResponse parse(ResponseType response) { String userId = null; Dictionary <String, List <LinkIDAttribute> > attributes = new Dictionary <string, List <LinkIDAttribute> >(); foreach (object item in response.Items) { AssertionType assertion = (AssertionType)item; SubjectType subject = assertion.Subject; NameIDType nameId = (NameIDType)subject.Items[0]; userId = nameId.Value; foreach (StatementAbstractType statement in assertion.Items) { if (statement is AttributeStatementType) { AttributeStatementType attributeStatement = (AttributeStatementType)statement; attributes = getAttributes(attributeStatement); } } } LinkIDPaymentResponse paymentResponse = findPaymentResponse(response); LinkIDExternalCodeResponse externalCodeResponse = findExternalCodeResponse(response); return(new LinkIDAuthnResponse(userId, attributes, paymentResponse, externalCodeResponse)); }
public static string GetSAMLResponse(string request, string username) { string destination = "https://login.microsoftonline.com/login.srf"; string recipient = "https://login.microsoftonline.com/login.srf"; string issuer = "https://accounts.google.com/o/saml2?idpid=C00s8nnu4"; //XDocument xdRequest = XDocument.Parse(request); XNamespace xnSAML2p = "urn:oasis:names:tc:SAML:2.0:protocol"; XNamespace xnSAML2 = "urn:oasis:names:tc:SAML:2.0:assertion"; XNamespace xnDS = "http://www.w3.org/2000/09/xmldsig#"; XDocument xdResponse = new XDocument(); var xeResponse = new XElement(xnSAML2p + "Response"); xeResponse.SetAttributeValue("Destination", destination); var responseId = Guid.NewGuid(); xeResponse.SetAttributeValue("ID", String.Format("_{0:N}", responseId)); //xeResponse.SetAttributeValue("InResponseTo", requestId); xdResponse.Add(xeResponse); //2019 - 12 - 11T15: 44:21.256Z var str = xdResponse.ToString(); var sb = new StringBuilder(); ResponseType response = new ResponseType(); // Response Main Area response.ID = "_" + Guid.NewGuid().ToString(); response.Destination = recipient; response.Version = "2.0"; response.IssueInstant = System.DateTime.UtcNow; NameIDType issuerForResponse = new NameIDType(); issuerForResponse.Value = issuer.Trim(); response.Issuer = issuerForResponse; StatusType status = new StatusType(); status.StatusCode = new StatusCodeType(); status.StatusCode.Value = "urn:oasis:names:tc:SAML:2.0:status:Success"; response.Status = status; return(""); }
/// <summary> /// Initializes a new instance of the <see cref="Saml2Options" /> class. /// </summary> public Saml2Options() { EnablePIILogging = false; WantAuthnRequestsSigned = false; ForwardChallenge = AuthenticationScheme; SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; SignOutScheme = AuthenticationScheme; AuthenticationScheme = Saml2Defaults.AuthenticationScheme; SignOutPath = new PathString("/signedout"); CallbackPath = new PathString("/saml2-signin"); DefaultRedirectUrl = new PathString("/"); RequireHttpsMetadata = true; ForceAuthn = true; NameIDType = new NameIDType(); IsPassive = false; VerifySignatureOnly = true; DefaultMetadataFolderLocation = "wwwroot"; DefaultMetadataFileName = "Metadata"; CreateMetadataFile = false; ServiceProvider = new ServiceProviderInfo() { HashAlgorithm = HashAlgorithmName.SHA256, AssertionConsumerServices = new IndexedEndpointType[] { new IndexedEndpointType() { Binding = ProtocolBindings.HTTP_Post, //must only allow POST index = 0, isDefault = true, isDefaultSpecified = true } }, SingleLogoutServices = new EndpointType[] { new EndpointType() { Binding = ProtocolBindings.HTTP_Post //must only allow Post back to sp } } }; WantAssertionsSigned = false; RequireMessageSigned = false; RequestIdCookieLifetime = TimeSpan.FromMinutes(10); RequestCookieId = new CookieBuilder() { IsEssential = CookieConsentNeeded, HttpOnly = true, SameSite = SameSiteMode.None, SecurePolicy = CookieSecurePolicy.SameAsRequest, Expiration = RequestIdCookieLifetime }; Events = new Saml2Events(); AllowUnsolicitedLogins = false; }
/// <summary> /// Identifies the subject. /// </summary> /// <param name="format">A URI reference representing the classification of string-based identifier information. If no value is specified then the value "nameid-format-unspecified" is in effect.</param> /// <param name="value">Value of the name</param> /// <param name="spProviderId">Name Identifier established by a service provider or affiliation providers for the entity.</param> /// <param name="nameQualifier">The security or administrative domain that qualifies the name.</param> /// <param name="spNameQualifier">Further qualifies a name with the name of the service provider or affiliaton provider.</param> /// <returns></returns> public SubjectBuilder SetNameId(string format, string value, string spProviderId = null, string nameQualifier = null, string spNameQualifier = null) { var nameIdType = new NameIDType { Format = format, Value = value, SPProvidedID = spProviderId, NameQualifier = nameQualifier, SPNameQualifier = spNameQualifier }; ReplaceIdentifier(nameIdType); return(this); }
public string getUsername(String userId) { NameIdentifierMappingQueryRequest request = new NameIdentifierMappingQueryRequest(); NameIDType nameId = new NameIDType(); nameId.Value = userId; request.NameIDMappingRequest = new NameIDMappingRequestType(); request.NameIDMappingRequest.Item = nameId; this.client.NameIdentifierMappingQuery(request); /* * NameIDMappingRequestType request = new NameIDMappingRequestType(); * this.client.NameIdentifierMappingQuery(request); */ return(null); }
private static void ValidateNameID(NameIDType nameId) { if (nameId == null) { throw new ArgumentNullException("nameId"); } if (string.IsNullOrEmpty(nameId.Format)) { return; } if (nameId.Format == Saml2Constants.NameIdentifierFormats.Unspecified) { if (string.IsNullOrEmpty(nameId.Value)) { throw new Exception("NameID with unspecified format attribute must have a value"); } } SamlHelper.Username = nameId.Value; }
private AttributeQueryType getAttributeQuery(string userId, string[] attributeNames) { AttributeQueryType attributeQuery = new AttributeQueryType(); SubjectType subject = new SubjectType(); NameIDType subjectName = new NameIDType(); subjectName.Value = userId; subject.Items = new Object[] { subjectName }; attributeQuery.Subject = subject; if (null != attributeNames) { List <AttributeType> attributes = new List <AttributeType>(); foreach (string attributeName in attributeNames) { AttributeType attribute = new AttributeType(); attribute.Name = attributeName; attributes.Add(attribute); } attributeQuery.Attribute = attributes.ToArray(); } return(attributeQuery); }
private static AssertionType CreateSamlAssertion(AuthnRequestType samlAuthRequest, string username) { var assertion = new AssertionType { Version = "2.0", IssueInstant = DateTime.UtcNow, ID = "_" + Guid.NewGuid(), Issuer = new NameIDType() { Value = $"{_context.Request.Scheme}://{_context.Request.Host}{_context.Request.PathBase}" } }; //Assertion Subject var subject = new SubjectType(); var subjectNameIdentifier = new NameIDType() { Value = username, Format = Saml2Constants.NameIdentifierFormats.Unspecified }; var subjectConfirmation = new SubjectConfirmationType() { Method = Saml2Constants.SubjectConfirmationMethods.HolderOfKey, SubjectConfirmationData = new SubjectConfirmationDataType() { NotOnOrAfter = DateTime.UtcNow.AddMinutes(ASSERTION_TIMEOUT_IN_MINUTES), Recipient = samlAuthRequest.AssertionConsumerServiceURL, InResponseTo = samlAuthRequest.ID } }; subject.Items = new object[] { subjectNameIdentifier, subjectConfirmation }; assertion.Subject = subject; //Assertion Conditions var conditions = new ConditionsType { NotBefore = DateTime.UtcNow, NotBeforeSpecified = true, NotOnOrAfter = DateTime.UtcNow.AddMinutes(ASSERTION_TIMEOUT_IN_MINUTES), NotOnOrAfterSpecified = true, //TODO: samlAuthRequest.Issuer.Value should be replaced with Items = new ConditionAbstractType[] { new AudienceRestrictionType() { Audience = new string[] { samlAuthRequest.Issuer.Value } } } }; assertion.Conditions = conditions; //Assertion AuthnStatement var authStatement = new AuthnStatementType() { AuthnInstant = DateTime.UtcNow, SessionIndex = assertion.ID }; var context = new AuthnContextType(); context.ItemsElementName = new[] { ItemsChoiceType5.AuthnContextClassRef }; context.Items = new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" }; authStatement.AuthnContext = context; //Assertion AttributeStatement var attributeStatement = new AttributeStatementType(); attributeStatement.Items = new AttributeType[] { //Add as many attributes as you want here, these are the user details that service provider wants, we can customise the attributes required // on the basis of service provider that requires this assertion new AttributeType { Name = "username", AttributeValue = username, NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" } }; assertion.Items = new StatementAbstractType[] { authStatement, attributeStatement }; return(assertion); }
/// <summary> /// GetPostSamlResponse - Returns a Base64 Encoded String with the SamlResponse in it. /// </summary> /// <param name="recipient">Recipient</param> /// <param name="issuer">Issuer</param> /// <param name="domain">Domain</param> /// <param name="subject">Subject</param> /// <param name="storeLocation">Certificate Store Location</param> /// <param name="storeName">Certificate Store Name</param> /// <param name="findType">Certificate Find Type</param> /// <param name="certLocation">Certificate Location</param> /// <param name="findValue">Certificate Find Value</param> /// <param name="certFile">Certificate File (used instead of the above Certificate Parameters)</param> /// <param name="certPassword">Certificate Password (used instead of the above Certificate Parameters)</param> /// <param name="attributes">A list of attributes to pass</param> /// <param name="signatureType">Whether to sign Response or Assertion</param> /// <returns>A base64Encoded string with a SAML response.</returns> public static string GetPostSamlResponse(string recipient, string issuer, string subject, string audience, string requestid, string nameIdPolicyFormat, StoreLocation storeLocation, StoreName storeName, X509FindType findType, string certFile, string certPassword, object findValue, Dictionary <string, string> attributes, SigningHelper.SignatureType signatureType, Models.IdPOptionsModel options) { ResponseType response = new ResponseType(); // Response Main Area response.ID = "_" + Guid.NewGuid().ToString("N"); response.Destination = recipient; response.Version = "2.0"; response.IssueInstant = System.DateTime.UtcNow; response.InResponseTo = requestid; NameIDType issuerForResponse = new NameIDType(); issuerForResponse.Value = issuer.Trim(); response.Issuer = issuerForResponse; StatusType status = new StatusType(); status.StatusCode = new StatusCodeType(); status.StatusCode.Value = "urn:oasis:names:tc:SAML:2.0:status:Success"; response.Status = status; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); if (options.UseNamespaces) { ns.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol"); ns.Add("saml2", "urn:oasis:names:tc:SAML:2.0:assertion"); ns.Add("ds", "http://www.w3.org/2000/09/xmldsig#"); } XmlSerializer responseSerializer = new XmlSerializer(response.GetType()); StringWriter stringWriter = new StringWriter(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.UTF8; settings.OmitXmlDeclaration = true; settings.Indent = true; XmlWriter responseWriter = XmlTextWriter.Create(stringWriter, settings); string samlString = string.Empty; AssertionType assertionType = SamlHelper.CreateSamlAssertion( issuer.Trim(), recipient.Trim(), subject.Trim(), audience.Trim(), nameIdPolicyFormat, attributes); response.Items = new AssertionType[] { assertionType }; responseSerializer.Serialize(responseWriter, response, ns); responseWriter.Close(); samlString = stringWriter.ToString(); samlString = samlString.Replace("SubjectConfirmationData", string.Format("SubjectConfirmationData NotOnOrAfter=\"{0:o}\" Recipient=\"{1}\" InResponseTo=\"{2:D}\" ", DateTime.UtcNow.AddMinutes(5), recipient, requestid)); stringWriter.Close(); XmlDocument doc = new XmlDocument(); //doc.LoadXml(samlString); byte[] samlBytes = Encoding.UTF8.GetBytes(samlString); var ms = new MemoryStream(samlBytes); doc.Load(ms); X509Certificate2 cert = null; if (System.IO.File.Exists(certFile)) { try { cert = new X509Certificate2(certFile, certPassword); } catch (Exception ex) { ; } } else { X509Store store = new X509Store(storeName, storeLocation); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection coll = store.Certificates.Find(findType, findValue, false); if (coll.Count < 1) { throw new ArgumentException("Unable to locate certificate"); } cert = coll[0]; store.Close(); } XmlElement signature = SigningHelper.SignDoc(doc, cert, "ID", signatureType == SigningHelper.SignatureType.Response ? response.ID : assertionType.ID, options); doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]); if (SamlHelper.Logger.IsDebugEnabled) { SamlHelper.Logger.DebugFormat( "Saml Assertion before encoding = {0}", doc.OuterXml.ToString()); } //string responseStr = doc.OuterXml; //byte[] base64EncodedBytes = // Encoding.UTF8.GetBytes(responseStr); if (options.IncludeXmlDeclaration) { //Create an XML declaration. XmlDeclaration xmldecl; xmldecl = doc.CreateXmlDeclaration("1.0", "UTF-8", "no"); //Add the new node to the document. XmlElement root = doc.DocumentElement; doc.InsertBefore(xmldecl, root); } byte[] base64EncodedBytes = Encoding.UTF8.GetBytes(doc.OuterXml); string returnValue = System.Convert.ToBase64String( base64EncodedBytes); return(returnValue); }
public static XmlElement GetSignature(string recipient, string issuer, string domain, string subject, StoreLocation storeLocation, StoreName storeName, X509FindType findType, string certFile, string certPassword, object findValue, Dictionary <string, string> attributes, SigningHelper.SignatureType signatureType) { ResponseType response = new ResponseType(); // Response Main Area response.ID = "_" + Guid.NewGuid().ToString(); response.Destination = recipient; response.Version = "2.0"; response.IssueInstant = System.DateTime.UtcNow; NameIDType issuerForResponse = new NameIDType(); issuerForResponse.Value = issuer.Trim(); response.Issuer = issuerForResponse; StatusType status = new StatusType(); status.StatusCode = new StatusCodeType(); status.StatusCode.Value = "urn:oasis:names:tc:SAML:2.0:status:Success"; response.Status = status; XmlSerializer responseSerializer = new XmlSerializer(response.GetType()); StringWriter stringWriter = new StringWriter(); XmlWriterSettings settings = new XmlWriterSettings(); settings.OmitXmlDeclaration = true; settings.Indent = true; settings.Encoding = Encoding.UTF8; XmlWriter responseWriter = XmlTextWriter.Create(stringWriter, settings); string samlString = string.Empty; AssertionType assertionType = CreateSamlAssertion( issuer.Trim(), recipient.Trim(), domain.Trim(), subject.Trim(), attributes); response.Items = new AssertionType[] { assertionType }; responseSerializer.Serialize(responseWriter, response); responseWriter.Close(); samlString = stringWriter.ToString(); samlString = samlString.Replace("SubjectConfirmationData", string.Format("SubjectConfirmationData NotOnOrAfter=\"{0:o}\" Recipient=\"{1}\"", DateTime.UtcNow.AddMinutes(5), recipient)); stringWriter.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(samlString); X509Certificate2 cert = null; cert = new X509Certificate2(certFile, certPassword); XmlElement signature = SigningHelper.SignDoc(doc, cert, "ID", signatureType == SigningHelper.SignatureType.Response ? response.ID : assertionType.ID); return(signature); }
/// <summary> /// GetPostSamlResponse - Returns a Base64 Encoded String with the SamlResponse in it. /// </summary> /// <param name="recipient">Recipient</param> /// <param name="issuer">Issuer</param> /// <param name="domain">Domain</param> /// <param name="subject">Subject</param> /// <param name="storeLocation">Certificate Store Location</param> /// <param name="storeName">Certificate Store Name</param> /// <param name="findType">Certificate Find Type</param> /// <param name="certLocation">Certificate Location</param> /// <param name="findValue">Certificate Find Value</param> /// <param name="certFile">Certificate File (used instead of the above Certificate Parameters)</param> /// <param name="certPassword">Certificate Password (used instead of the above Certificate Parameters)</param> /// <param name="attributes">A list of attributes to pass</param> /// <param name="signatureType">Whether to sign Response or Assertion</param> /// <returns>A base64Encoded string with a SAML response.</returns> public static string BuildPostSamlResponse(string recipient, string issuer, string domain, string subject, StoreLocation storeLocation, StoreName storeName, X509FindType findType, string certFile, string certPassword, object findValue, Dictionary <string, string> attributes, SigningHelper.SignatureType signatureType) { ResponseType response = new ResponseType { // Response Main Area ID = "_" + Guid.NewGuid().ToString(), Destination = recipient, Version = "2.0", IssueInstant = DateTime.UtcNow }; NameIDType issuerForResponse = new NameIDType { Value = issuer.Trim() }; response.Issuer = issuerForResponse; StatusType status = new StatusType { StatusCode = new StatusCodeType() }; status.StatusCode.Value = "urn:oasis:names:tc:SAML:2.0:status:Success"; response.Status = status; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol"); ns.Add("saml2", "urn:oasis:names:tc:SAML:2.0:assertion"); XmlSerializer responseSerializer = new XmlSerializer(response.GetType()); StringWriter stringWriter = new StringWriter(); XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, Encoding = Encoding.UTF8 }; XmlWriter responseWriter = XmlWriter.Create(stringWriter, settings); string samlString = string.Empty; AssertionType assertionType = Saml2Helper.CreateSamlAssertion( issuer.Trim(), recipient.Trim(), domain.Trim(), subject.Trim(), attributes); response.Items = new AssertionType[] { assertionType }; responseSerializer.Serialize(responseWriter, response, ns); responseWriter.Close(); samlString = stringWriter.ToString(); samlString = samlString.Replace("SubjectConfirmationData", string.Format("SubjectConfirmationData NotOnOrAfter=\"{0:o}\" Recipient=\"{1}\"", DateTime.UtcNow.AddMinutes(5), recipient)); samlString = samlString.Replace("<saml2:Assertion ", "<saml2:Assertion xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" "); samlString = samlString.Replace("<saml2:AuthnContextClassRef>AuthnContextClassRef</saml2:AuthnContextClassRef>", "<saml2:AuthnContextClassRef>" + issuer + "</saml2:AuthnContextClassRef>"); stringWriter.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(samlString); X509Certificate2 cert = null; if (System.IO.File.Exists(certFile)) { cert = new X509Certificate2(certFile, certPassword); } else { X509Store store = new X509Store(storeName, storeLocation); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); X509Certificate2Collection CertCol = store.Certificates; //foreach (X509Certificate2 c in CertCol) //{ // if (c.Subject.Contains(findValue.ToString())) // { // cert = c; // break; // } //} X509Certificate2Collection coll = store.Certificates.Find(findType, findValue.ToString(), false); //if (cert == null) //{ // throw new ArgumentException("Unable to locate certificate"); //} if (coll.Count < 1) { throw new ArgumentException("Unable to locate certificate"); } cert = coll[0]; store.Close(); } XmlElement signature = SigningHelper.SignDoc(doc, cert, response.ID); doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]); string responseStr = doc.OuterXml; byte[] base64EncodedBytes = Encoding.UTF8.GetBytes(responseStr); string returnValue = System.Convert.ToBase64String( base64EncodedBytes); return(returnValue); }
/// <REMARKS> /// AuthenticateSAMLResponse supports SP-Initiated and IDP-Initated, POST /// Does not pass specific SAML status values back to the caller; caller sends SAML Failed or Success status /// </REMARKS> internal static bool AuthenticateSamlResponse() { //Authenticated SAML Response will have the SAML token, transform the token into PTS Credential, create the principal, authenticated=true, create the SP cookie string parameterSamlResponse = HttpContext.Current.Request.Form[Helpers.Names.HttpParameterResponseSaml]; if (string.IsNullOrEmpty(parameterSamlResponse)) { return(HttpContext.Current.Request.IsAuthenticated); } //Validate SAML Response string decodedSamlResponse = Helpers.Helper.Utf8Base64DecodeString(parameterSamlResponse); XmlDocument xmlResponse = Helpers.Helper.ReadyXmlDocument; xmlResponse.LoadXml(decodedSamlResponse); ResponseType response = Helpers.Helper.DeserializeXmlDocumentToType <ResponseType>(xmlResponse); XmlElement xmlSignature = Saml.Helper.SelectXMLElement(xmlResponse, Names.SAMLNamesElementAssertionSignature, SignedXml.XmlDsigNamespaceUrl); //SAML Response objects are Federated; if the response is verified then the subject is trusted (authenticated) //However, from Federated IDPs the assertions must match the PTS Endpoint Claim set registered in SQL if (xmlSignature == null || !Saml.Helper.VerifySignedXMLElement(xmlResponse.DocumentElement, xmlSignature)) { return(HttpContext.Current.Request.IsAuthenticated); } //From SAML Response assertions and RelayState, validate the user and build the PTS authenticated credential AssertionType assertion = response.Items.Where(t => t.GetType().FullName == typeof(AssertionType).FullName)?.First() as AssertionType; NameIDType nameId = assertion.Subject.Items.Where(t => t.GetType().FullName == typeof(NameIDType).FullName)?.First() as NameIDType; AttributeStatementType statement = assertion?.Items.Where(t => t.GetType().FullName == typeof(AttributeStatementType).FullName)?.First() as AttributeStatementType; List <AttributeType> attributeList = statement?.Items.Select(a => (AttributeType)a)?.ToList(); string subjectNameId = nameId?.Value; //Response message not expired; eliminates replay attack if (DateTime.Now >= assertion.Conditions.NotOnOrAfter) { return(HttpContext.Current.Request.IsAuthenticated); } Credential credential = new Credential { EntityId = subjectNameId, ClaimsId = assertion.Issuer.Value, Refresh = true }; //Claim set valid; eliminate man-in-the-middle attack if (!AuthenticateSamlAssertion(attributeList, ref credential)) { return(HttpContext.Current.Request.IsAuthenticated); } XmlDocument xmlCredential = Helpers.Helper.SerializeTypeToXmlDocument(credential); //Deflate (W3C) and Encrypt (RSA) the PTS SSO XML Document credential... string credentialDeflatedEncrypted = Helpers.Helper.XmlDocumentDeflateEncrypt(xmlCredential); //Create Authenticated Principal from PTS Credential ClaimsIdentity claimsIdentity = new ClaimsIdentity( new GenericIdentity(credential.Email, Helpers.Names.PrincipalType), credential.Claims.Select(c => new System.Security.Claims.Claim($"{c.Name}:{c.FriendlyName}", c.Value, c.NameFormat, c.EntityId)) //Inserting a Generic Identity into the Claims Identity makes the User context both claim and role aware... ); HttpContext.Current.User = new GenericPrincipal(claimsIdentity, credential.Roles.Select(r => r.Name).ToArray()); //Set PTS Authentication Session cookie; note the IIS Pipeline cache is not available in the application authenticaiton event //The only other cache choice for user credentials is another call to SQL Server with each IIS Pipeline request HttpContext.Current.Response.Cookies.Add(new HttpCookie(Helpers.Names.HttpCookiePtsSso) { //IDP root session cookie, not persistant, not client script accessible, value is segmented, encrypted and defalted (W3C/RSA compliant) Expires = DateTime.MinValue, HttpOnly = true, Path = Helpers.Names.PathRoot, Value = credentialDeflatedEncrypted }); return(HttpContext.Current.Request.IsAuthenticated); }
/// <summary> /// Creates a Version 1.1 Saml Assertion /// </summary> /// <param name="issuer">Issuer</param> /// <param name="subject">Subject</param> /// <param name="attributes">Attributes</param> /// <returns>returns a Version 1.1 Saml Assertion</returns> private static AssertionType CreateSamlAssertion(string issuer, string recipient, string domain, string subject, Dictionary <string, string> attributes) { // Here we create some SAML assertion with ID and Issuer name. AssertionType assertion = new AssertionType(); assertion.ID = "_" + Guid.NewGuid().ToString(); NameIDType issuerForAssertion = new NameIDType(); issuerForAssertion.Value = issuer.Trim(); assertion.Issuer = issuerForAssertion; assertion.Version = "2.0"; assertion.IssueInstant = System.DateTime.UtcNow; //Not before, not after conditions ConditionsType conditions = new ConditionsType(); conditions.NotBefore = DateTime.UtcNow; conditions.NotBeforeSpecified = true; conditions.NotOnOrAfter = DateTime.UtcNow.AddMinutes(5); conditions.NotOnOrAfterSpecified = true; AudienceRestrictionType audienceRestriction = new AudienceRestrictionType(); audienceRestriction.Audience = new string[] { domain.Trim() }; conditions.Items = new ConditionAbstractType[] { audienceRestriction }; //Name Identifier to be used in Saml Subject NameIDType nameIdentifier = new NameIDType(); nameIdentifier.NameQualifier = domain.Trim(); nameIdentifier.Value = subject.Trim(); SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType(); SubjectConfirmationDataType subjectConfirmationData = new SubjectConfirmationDataType(); subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer"; subjectConfirmation.SubjectConfirmationData = subjectConfirmationData; // // Create some SAML subject. SubjectType samlSubject = new SubjectType(); AttributeStatementType attrStatement = new AttributeStatementType(); AuthnStatementType authStatement = new AuthnStatementType(); authStatement.AuthnInstant = DateTime.UtcNow; AuthnContextType context = new AuthnContextType(); context.ItemsElementName = new ItemsChoiceType5[] { ItemsChoiceType5.AuthnContextClassRef }; context.Items = new object[] { "AuthnContextClassRef" }; authStatement.AuthnContext = context; samlSubject.Items = new object[] { nameIdentifier, subjectConfirmation }; assertion.Subject = samlSubject; IPHostEntry ipEntry = Dns.GetHostEntry(System.Environment.MachineName); SubjectLocalityType subjectLocality = new SubjectLocalityType(); subjectLocality.Address = ipEntry.AddressList[0].ToString(); attrStatement.Items = new AttributeType[attributes.Count]; int i = 0; // Create userName SAML attributes. foreach (KeyValuePair <string, string> attribute in attributes) { AttributeType attr = new AttributeType(); attr.Name = attribute.Key; attr.NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"; attr.AttributeValue = new object[] { attribute.Value }; attrStatement.Items[i] = attr; i++; } assertion.Conditions = conditions; assertion.Items = new StatementAbstractType[] { authStatement, attrStatement }; return(assertion); }
/// <summary> /// Creates a SAML 2.0 Assertion Segment for a Response /// Simple implmenetation assuming a list of string key and value pairs /// </summary> /// <param name="Issuer"></param> /// <param name="AssertionExpirationMinutes"></param> /// <param name="Audience"></param> /// <param name="Subject"></param> /// <param name="Recipient"></param> /// <param name="Attributes">Dictionary of string key, string value pairs</param> /// <returns>Assertion to sign and include in Response</returns> private static AssertionType CreateSAML20Assertion(string Issuer, int AssertionExpirationMinutes, string Audience, string Subject, string Recipient, Dictionary <string, string> Attributes) { AssertionType NewAssertion = new AssertionType() { Version = "2.0", IssueInstant = DateTime.Now,//DateTime.UtcNow, ID = "_" + System.Guid.NewGuid().ToString() }; // Create Issuer NewAssertion.Issuer = new NameIDType() { Value = Issuer.Trim() }; // Create Assertion Subject SubjectType subject = new SubjectType(); NameIDType subjectNameIdentifier = new NameIDType() { Value = Subject.Trim(), Format = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" }; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType() { Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer", SubjectConfirmationData = new SubjectConfirmationDataType() { NotOnOrAfter = DateTime.Now.AddMinutes(AssertionExpirationMinutes), Recipient = Recipient } }; //{ NotOnOrAfter = DateTime.UtcNow.AddMinutes(AssertionExpirationMinutes), Recipient = Recipient } }; subject.Items = new object[] { subjectNameIdentifier, subjectConfirmation }; NewAssertion.Subject = subject; // Create Assertion Conditions ConditionsType conditions = new ConditionsType(); conditions.NotBefore = DateTime.Now; //DateTime.UtcNow; conditions.NotBeforeSpecified = true; conditions.NotOnOrAfter = DateTime.Now.AddMinutes(AssertionExpirationMinutes); //DateTime.UtcNow.AddMinutes(AssertionExpirationMinutes); conditions.NotOnOrAfterSpecified = true; conditions.Items = new ConditionAbstractType[] { new AudienceRestrictionType() { Audience = new string[] { Audience.Trim() } } }; NewAssertion.Conditions = conditions; // Add AuthnStatement and Attributes as Items AuthnStatementType authStatement = new AuthnStatementType() { AuthnInstant = DateTime.Now, SessionIndex = NewAssertion.ID }; //{ AuthnInstant = DateTime.UtcNow, SessionIndex = NewAssertion.ID }; AuthnContextType context = new AuthnContextType(); context.ItemsElementName = new ItemsChoiceType5[] { ItemsChoiceType5.AuthnContextClassRef }; context.Items = new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" }; authStatement.AuthnContext = context; AttributeStatementType attributeStatement = new AttributeStatementType(); attributeStatement.Items = new AttributeType[Attributes.Count]; int i = 0; foreach (KeyValuePair <string, string> attribute in Attributes) { attributeStatement.Items[i] = new AttributeType() { Name = attribute.Key, AttributeValue = new object[] { attribute.Value }, NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" }; i++; } NewAssertion.Items = new StatementAbstractType[] { authStatement, attributeStatement }; return(NewAssertion); }
/// <summary> /// Creates the logout request. /// The "LogoutRequest" message MUST be signed if the HTTP POST or Redirect binding is used. /// Logout request MUST be signed according to http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf Sect 4.4.3.1 /// </summary> /// <param name="options">The options.</param> /// <param name="logoutRequestId">The logout request identifier.</param> /// <param name="sessionIndex">Index of the session.</param> /// <param name="nameId">The name identifier.</param> /// <param name="relayState">State of the relay.</param> /// <param name="sendSignoutTo">The send signout to.</param> /// <returns></returns> /// <exception cref="ArgumentException">Signing key must be an instance of either RSA or DSA.</exception> public string CreateLogoutRequest(Saml2Options options, string logoutRequestId, string sessionIndex, string nameId, string relayState, string sendSignoutTo) { NameIDType entityID = new NameIDType() { Value = options.ServiceProvider.EntityId }; var singleLogoutService = options.Configuration.SingleLogoutServices.FirstOrDefault(x => x.Binding == options.SingleLogoutServiceProtocolBinding); LogoutRequest logoutRequest = new LogoutRequest() { ID = logoutRequestId, Issuer = entityID, Version = Saml2Constants.Version, Reason = Saml2Constants.Reasons.User, SessionIndex = new string[] { sessionIndex }, Destination = singleLogoutService.Location.ToString(), IssueInstant = DateTime.UtcNow, Item = new NameIDType() { Format = options.NameIDType.Format, NameQualifier = options.NameIDType.NameQualifier, SPProvidedID = options.NameIDType.SPProvidedID, SPNameQualifier = options.NameIDType.SPNameQualifier, Value = options.NameIDType.Value } }; string singleLogoutUrl = options.Configuration.SingleLogoutServices.FirstOrDefault().Location; //serialize AuthnRequest to xml string string xmlTemplate = string.Empty; XmlSerializer xmlSerializer = new XmlSerializer(typeof(LogoutRequest)); using (MemoryStream memStm = new MemoryStream()) { xmlSerializer.Serialize(memStm, logoutRequest); memStm.Position = 0; xmlTemplate = new StreamReader(memStm).ReadToEnd(); } //create xml document from string XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlTemplate); xmlDoc.PreserveWhitespace = false; string request = xmlDoc.OuterXml; var result = new StringBuilder(); result.AddMessageParameter(request, null); result.AddRelayState(request, relayState); if (options.hasCertificate) { X509Certificate2 spCertificate = GetServiceProviderCertficate(options); string hashingAlgorithm = options.Configuration.Signature.SignedInfo.SignatureMethod; AsymmetricAlgorithm spPrivateKey = spCertificate.PrivateKey; // Check if the key is of a supported type. [SAMLBind] sect. 3.4.4.1 specifies this. if (!(spPrivateKey is RSA || spPrivateKey is DSA || spPrivateKey == null)) { throw new ArgumentException("Signing key must be an instance of either RSA or DSA."); } AddSignature(result, spPrivateKey, hashingAlgorithm, options.ServiceProvider.HashAlgorithm); } return($"{singleLogoutUrl}?{result}"); }
/// <summary> /// /// </summary> /// <param name="UUID"></param> /// <param name="Destination"></param> /// <param name="ConsumerServiceURL"></param> /// <param name="certFile"></param> /// <param name="certPassword"></param> /// <param name="storeLocation"></param> /// <param name="storeName"></param> /// <param name="findType"></param> /// <param name="findValue"></param> /// <param name="signatureType"></param> /// <returns></returns> public static string BuildPostSamlRequest(string UUID, string Destination, string ConsumerServiceURL, int SecurityLevel, string certFile, string certPassword, StoreLocation storeLocation, StoreName storeName, X509FindType findType, object findValue, SigningHelper.SignatureType signatureType, string IdentityProvider, int Enviroment) { AuthnRequestType MyRequest = new AuthnRequestType { ID = UUID, Version = "2.0" }; DateTime now = DateTime.UtcNow; DateTime after = now.AddMinutes(10); string nowString = String.Empty; string afterString = String.Empty; if (IdentityProvider.Contains("sielte")) { // SIELTE nowString = now.AddMinutes(-2).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"); afterString = after.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"); } else { // POSTE - TIM - INFOCERT nowString = now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"); afterString = after.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"); } MyRequest.IssueInstant = nowString; if (SecurityLevel > 1) { MyRequest.ForceAuthn = true; MyRequest.ForceAuthnSpecified = true; } MyRequest.Destination = Destination; MyRequest.AssertionConsumerServiceIndex = (ushort)Enviroment; MyRequest.AssertionConsumerServiceIndexSpecified = true; MyRequest.AttributeConsumingServiceIndex = 1; MyRequest.AttributeConsumingServiceIndexSpecified = true; NameIDType IssuerForRequest = new NameIDType { Value = ConsumerServiceURL.Trim(), Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", NameQualifier = ConsumerServiceURL }; MyRequest.Issuer = IssuerForRequest; NameIDPolicyType NameIdPolicyForRequest = new NameIDPolicyType { Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", AllowCreate = true, AllowCreateSpecified = true }; MyRequest.NameIDPolicy = NameIdPolicyForRequest; ConditionsType Conditional = new ConditionsType(); if (IdentityProvider.Contains("sielte")) { // SIELTE Conditional.NotBefore = nowString; } else { // POSTE - TIM - INFOCERT Conditional.NotBefore = now.AddMinutes(-2).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"); } Conditional.NotBeforeSpecified = true; Conditional.NotOnOrAfter = afterString; Conditional.NotOnOrAfterSpecified = true; MyRequest.Conditions = Conditional; RequestedAuthnContextType RequestedAuthn = new RequestedAuthnContextType { Comparison = AuthnContextComparisonType.minimum, ComparisonSpecified = true, ItemsElementName = new ItemsChoiceType7[] { ItemsChoiceType7.AuthnContextClassRef }, Items = new string[] { "https://www.spid.gov.it/SpidL" + SecurityLevel.ToString() } }; MyRequest.RequestedAuthnContext = RequestedAuthn; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("saml2p", "urn:oasis:names:tc:SAML:2.0:protocol"); //ns.Add("saml2", "urn:oasis:names:tc:SAML:2.0:assertion"); XmlSerializer responseSerializer = new XmlSerializer(MyRequest.GetType()); StringWriter stringWriter = new StringWriter(); XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, Encoding = Encoding.UTF8 }; XmlWriter responseWriter = XmlTextWriter.Create(stringWriter, settings); responseSerializer.Serialize(responseWriter, MyRequest, ns); responseWriter.Close(); string samlString = string.Empty; samlString = stringWriter.ToString(); stringWriter.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(samlString); X509Certificate2 cert = null; if (System.IO.File.Exists(certFile)) { cert = new X509Certificate2(certFile, certPassword); } else { X509Store store = new X509Store(storeName, storeLocation); store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); X509Certificate2Collection CertCol = store.Certificates; X509Certificate2Collection coll = store.Certificates.Find(findType, findValue.ToString(), false); if (coll.Count < 1) { throw new ArgumentException("Unable to locate certificate"); } cert = coll[0]; store.Close(); } XmlElement signature = SigningHelper.SignDoc(doc, cert, UUID); doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]); string responseStr = doc.OuterXml; //byte[] base64EncodedBytes = // Encoding.UTF8.GetBytes(responseStr); //string returnValue = System.Convert.ToBase64String( // base64EncodedBytes); return("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + responseStr); }
public new void ProcessRequest(HttpContext context) { try { // ***** RESPONSE ***** if (!String.IsNullOrEmpty(context.Request[HttpBindingConstants.SAMLResponse])) { // Recupera Response string samlresponse = context.Request[HttpBindingConstants.SAMLResponse]; XmlDocument doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(samlresponse); // Verifica Signature do Response if (XmlSignatureUtils.VerifySignature(doc)) { SAMLResponse = SAMLUtility.DeserializeFromXmlString <ResponseType>(doc.InnerXml); if (SAMLResponse.Items.Length > 0) { for (int i = 0; i < SAMLResponse.Items.Length; i++) { if (SAMLResponse.Items[i] is AssertionType) { NameIDType nameID = null; AssertionType assertion = (AssertionType)SAMLResponse.Items[i]; for (int j = 0; j < assertion.Subject.Items.Length; j++) { if (assertion.Subject.Items[j] is NameIDType) { nameID = (NameIDType)assertion.Subject.Items[j]; } } if (nameID != null) { SignHelper.AutenticarUsuarioDaRespostaDoSaml(nameID.Value); } } // Armazena dados do sistema emissor do Request // em Cookie de sistemas autenticados AddSAMLCookie(context); } } context.Response.Redirect(HttpUtility.UrlDecode(context.Request[HttpBindingConstants.RelayState]), false); } else { throw new ValidationException("Não foi possível encontrar assinatura."); } } // ***** REQUEST ***** else if (!String.IsNullOrEmpty(context.Request[HttpBindingConstants.SAMLRequest])) { throw new NotImplementedException(); } else { // Carrega as configurações do ServiceProvider ServiceProvider config = ServiceProvider.GetConfig(); ServiceProviderEndpoint spend = SAMLUtility.GetServiceProviderEndpoint(config.ServiceEndpoint, SAMLTypeSSO.signon); // Verifica configuração do ServiceProvider para signon if (spend == null) { throw new ValidationException("Não foi possível encontrar as configurações do ServiceProvider para signon."); } // Verifica se usuário está autenticado, caso não envia um Resquest solicitando autenticação if (!UsuarioWebIsValid()) { SAMLRequest = new SAMLAuthnRequest(); SAMLRequest.Issuer = config.id; SAMLRequest.AssertionConsumerServiceURL = context.Request.Url.AbsoluteUri; HttpRedirectBinding binding = new HttpRedirectBinding(SAMLRequest, spend.localpath); binding.SendRequest(context, spend.redirectUrl); } else { HttpContext.Current.Response.Redirect(spend.localpath, false); HttpContext.Current.ApplicationInstance.CompleteRequest(); } } } catch (ValidationException ex) { ErrorMessage(ex.Message); } catch (Exception ex) { ApplicationWEB._GravaErro(ex); ErrorMessage("Não foi possível atender a solicitação."); } }
public void TestAuthnRequest() { AuthnRequestType authnRequest = new AuthnRequestType(); authnRequest.ID = "test-id"; authnRequest.AssertionConsumerServiceURL = "http://test.assertion.consumer"; authnRequest.Destination = "http://destination"; authnRequest.ForceAuthn = true; authnRequest.ProtocolBinding = "urn:test:protocol:binding"; authnRequest.Version = "2.0"; authnRequest.IssueInstant = DateTime.Now.ToUniversalTime(); NameIDType issuer = new NameIDType(); issuer.Value = "test-issuer"; authnRequest.Issuer = issuer; NameIDPolicyType nameIdPolicy = new NameIDPolicyType(); nameIdPolicy.AllowCreate = true; nameIdPolicy.AllowCreateSpecified = true; authnRequest.NameIDPolicy = nameIdPolicy; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); ns.Add("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); //ns.Add("ds", "http://www.w3.org/2000/09/xmldsig#"); XmlRootAttribute xRoot = new XmlRootAttribute(); xRoot.ElementName = "AuthnRequest"; xRoot.Namespace = "urn:oasis:names:tc:SAML:2.0:protocol"; XmlSerializer serializer = new XmlSerializer(typeof(AuthnRequestType), xRoot); MemoryStream memoryStream = new MemoryStream(); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); serializer.Serialize(xmlTextWriter, authnRequest, ns); memoryStream = (MemoryStream)xmlTextWriter.BaseStream; string result = new UTF8Encoding().GetString(memoryStream.ToArray()); Console.WriteLine("result: " + result); XmlDocument document = new XmlDocument(); memoryStream.Seek(0, SeekOrigin.Begin); document.Load(memoryStream); String xmlString = document.OuterXml; Console.WriteLine("DOM result: " + xmlString); RSACryptoServiceProvider Key = new RSACryptoServiceProvider(); SignedXml signedXml = new SignedXml(document); signedXml.SigningKey = Key; Signature signature = signedXml.Signature; signature.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; Reference reference = new Reference("#" + authnRequest.ID); XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); reference.AddTransform(env); XmlDsigExcC14NTransform excC14NTransform = new XmlDsigExcC14NTransform("ds saml samlp"); reference.AddTransform(excC14NTransform); signature.SignedInfo.AddReference(reference); signedXml.ComputeSignature(); XmlElement xmlDigitalSignature = signedXml.GetXml(); document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true)); result = document.OuterXml; Console.WriteLine("result: " + result); XmlTextWriter xmltw = new XmlTextWriter(TestConstants.workDir + "\\test.xml", new UTF8Encoding(false)); document.WriteTo(xmltw); xmltw.Close(); }
/// <summary> /// Generates a SAML v2.0 Authentication Request with HTTP Browser Post Binding. /// The return string containing the request is NOT Base64 encoded. /// </summary> /// <param name="linkIDContext">the linkID authentication/payment configuration</param> /// <returns>SAML request</returns> public static AuthnRequestType generateAuthnRequest(LinkIDAuthenticationContext linkIDContext) { AuthnRequestType authnRequest = new AuthnRequestType(); authnRequest.ForceAuthn = true; authnRequest.ID = Guid.NewGuid().ToString(); authnRequest.Version = "2.0"; authnRequest.IssueInstant = DateTime.UtcNow; NameIDType issuer = new NameIDType(); issuer.Value = linkIDContext.applicationName; authnRequest.Issuer = issuer; NameIDPolicyType nameIdPolicy = new NameIDPolicyType(); nameIdPolicy.AllowCreate = true; nameIdPolicy.AllowCreateSpecified = true; authnRequest.NameIDPolicy = nameIdPolicy; Dictionary <string, string> deviceContextMap = linkIDContext.getDeviceContextMap(); DeviceContextType deviceContext = null; if (null != deviceContextMap && deviceContextMap.Count > 0) { deviceContext = new DeviceContextType(); List <AttributeType> attributes = new List <AttributeType>(); foreach (string deviceContextKey in deviceContextMap.Keys) { string deviceContextValue = deviceContextMap[deviceContextKey]; AttributeType attribute = new AttributeType(); attribute.Name = deviceContextKey; attribute.AttributeValue = new object[] { deviceContextValue }; attributes.Add(attribute); deviceContext.Items = attributes.ToArray(); } } SubjectAttributesType subjectAttributes = null; if (null != linkIDContext.attributeSuggestions && linkIDContext.attributeSuggestions.Count > 0) { subjectAttributes = new SubjectAttributesType(); List <AttributeType> attributes = new List <AttributeType>(); foreach (string attributeName in linkIDContext.attributeSuggestions.Keys) { List <object> values = linkIDContext.attributeSuggestions[attributeName]; AttributeType attribute = new AttributeType(); attribute.Name = attributeName; attribute.AttributeValue = values.ToArray(); attributes.Add(attribute); subjectAttributes.Items = attributes.ToArray(); } } PaymentContextType paymentContextType = null; if (null != linkIDContext.paymentContext) { Dictionary <String, String> paymentContextDict = linkIDContext.paymentContext.toDictionary(); paymentContextType = new PaymentContextType(); List <AttributeType> attributes = new List <AttributeType>(); foreach (string paymentContextKey in paymentContextDict.Keys) { string value = paymentContextDict[paymentContextKey]; AttributeType attribute = new AttributeType(); attribute.Name = paymentContextKey; attribute.AttributeValue = new object[] { value }; attributes.Add(attribute); paymentContextType.Items = attributes.ToArray(); } } CallbackType callbackType = null; if (null != linkIDContext.callback) { Dictionary <String, String> callbackDict = linkIDContext.callback.toDictionary(); callbackType = new CallbackType(); List <AttributeType> attributes = new List <AttributeType>(); foreach (string callbackKey in callbackDict.Keys) { string value = callbackDict[callbackKey]; AttributeType attribute = new AttributeType(); attribute.Name = callbackKey; attribute.AttributeValue = new object[] { value }; attributes.Add(attribute); callbackType.Items = attributes.ToArray(); } } if (null != deviceContext || null != subjectAttributes || null != paymentContextType || null != callbackType) { ExtensionsType extensions = new ExtensionsType(); List <XmlElement> extensionsList = new List <XmlElement>(); if (null != subjectAttributes) { extensionsList.Add(toXmlElement(subjectAttributes)); } if (null != deviceContext) { extensionsList.Add(toXmlElement(deviceContext)); } if (null != paymentContextType) { extensionsList.Add(toXmlElement(paymentContextType)); } if (null != callbackType) { extensionsList.Add(toXmlElement(callbackType)); } extensions.Any = extensionsList.ToArray(); authnRequest.Extensions = extensions; } return(authnRequest); }
/// <summary> /// /// </summary> /// <param name="context"></param> /// <returns></returns> private XmlDocument GenerateResponseMetadata(SAMLContext context, string id) { DateTime now = DateTime.UtcNow; MemoryStream stream = new MemoryStream(); StreamReader reader; XmlTextReader xmlReader; ResponseType response = new ResponseType(); response.ID = id; response.InResponseTo = context.RequestID; response.Version = SAMLConstants.SAML_VERSION; response.IssueInstant = now; response.Destination = context.AssertionConsumer; response.Consent = SAMLConstants.CONSENT; response.Issuer = new NameIDType(); response.Issuer.Value = thisIssuer; response.Issuer.Format = SAMLConstants.ThisIssuerFormat; response.Status = new StatusType(); response.Status.StatusCode = new StatusCodeType(); response.Status.StatusCode.Value = SAMLConstants.StatusCode.statusCode[context.StatusCode]; if (context.StatusCode != SAMLConstants.StatusCode.SUCCESS) { response.Status.StatusCode.StatusCode = new StatusCodeType(); response.Status.StatusCode.StatusCode.Value = SAMLConstants.StatusCode.statusCode[context.SubStatusCode]; response.Status.StatusMessage = context.StatusMessage; } AssertionType assertion = new AssertionType(); assertion.ID = "_" + Guid.NewGuid().ToString(); assertion.Version = SAMLConstants.SAML_VERSION; assertion.IssueInstant = now; assertion.Issuer = new NameIDType(); assertion.Issuer.Value = thisIssuer; assertion.Issuer.Format = SAMLConstants.ThisIssuerFormat; assertion.Subject = new SubjectType(); NameIDType nameId = new NameIDType(); nameId.Format = "urn:oasis:names:tc:SAML:1.1:nameid- format:unspecified"; //nameId.NameQualifier = "http://C-PEPS.gov.xx"; nameId.Value = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType(); subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer"; subjectConfirmation.SubjectConfirmationData = new SubjectConfirmationDataType(); subjectConfirmation.SubjectConfirmationData.Address = context.SubjectAddress; subjectConfirmation.SubjectConfirmationData.InResponseTo = context.RequestID; //subjectConfirmation.SubjectConfirmationData.NotBeforeString = "2010-02-03T17:06:18.099Z"; subjectConfirmation.SubjectConfirmationData.NotOnOrAfterString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now.AddMinutes(validTimeframe)); subjectConfirmation.SubjectConfirmationData.Recipient = context.Issuer; assertion.Subject.Items = new object[] { nameId, subjectConfirmation }; assertion.Conditions = new ConditionsType(); assertion.Conditions.NotBeforeString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now); assertion.Conditions.NotOnOrAfterString = String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", now.AddMinutes(validTimeframe)); AudienceRestrictionType audience = new AudienceRestrictionType(); audience.Audience = new string[] { context.Issuer }; // FIXME assertion.Conditions.Items = new ConditionAbstractType[] { audience, new OneTimeUseType() }; AuthnStatementType authnStatement = new AuthnStatementType(); authnStatement.AuthnInstant = now; authnStatement.AuthnContext = new AuthnContextType(); List <AttributeElement> attributes = context.GetAttributes(); object[] attributesDescription = new AttributeType[attributes.Count]; AttributeType attr; XmlAttribute statusAttr; int i = 0; foreach (AttributeElement element in attributes) { attr = new AttributeType(); attr.Name = element.AttrName; attr.NameFormat = element.NameFormat; if (context.StatusCode == SAMLConstants.StatusCode.SUCCESS) { if (element.AttrStatus == SAMLConstants.AttributeStatus.AVAILABLE && element.AttrValue != null) { attr.AttributeValue = new object[] { element.AttrValue } } ; if (element.AttrStatus >= 0) { statusAttr = new XmlDocument(). CreateAttribute(SAMLConstants.ATTRIBUTE_STATUS_STR, SAMLConstants.NS_STORK_ASSER); statusAttr.Value = element.Status; attr.AnyAttr = new XmlAttribute[] { statusAttr }; } } attributesDescription[i++] = attr; } AttributeStatementType attributeStatement = new AttributeStatementType(); attributeStatement.Items = attributesDescription; assertion.Items = new StatementAbstractType[] { authnStatement, attributeStatement }; response.Items = new object[] { assertion }; stream = new MemoryStream(); Serialize(response, stream); reader = new StreamReader(stream); stream.Seek(0, SeekOrigin.Begin); xmlReader = new XmlTextReader(new StringReader(reader.ReadToEnd())); return(Deserialize <XmlDocument>(xmlReader)); }
/// <summary> /// Creates the authn request. /// </summary> /// <param name="options">The options.</param> /// <param name="authnRequestId">The authn request identifier.</param> /// <param name="relayState">State of the relay.</param> /// <param name="assertionConsumerServiceUrl">The assertion consumer service URL.</param> /// <returns></returns> /// <exception cref="ArgumentException">Signing key must be an instance of either RSA or DSA.</exception> public string CreateAuthnRequest(Saml2Options options, string authnRequestId, string relayState, string assertionConsumerServiceUrl) { NameIDType entityID = new NameIDType() { Value = options.ServiceProvider.EntityId }; var singleSignOnService = options.Configuration.SingleSignOnServices.FirstOrDefault(x => x.Binding == options.AssertionConsumerServiceProtocolBinding); X509Certificate2 spCertificate = GetServiceProviderCertficate(options); AuthnRequest authnRequest = new AuthnRequest() { ID = authnRequestId, Issuer = entityID, Version = Saml2Constants.Version, ForceAuthn = options.ForceAuthn, ForceAuthnSpecified = true, IsPassive = options.IsPassive, IsPassiveSpecified = true, NameIDPolicy = new NameIDPolicyType() { Format = options.NameIDType.Format, SPNameQualifier = options.NameIDType.SPNameQualifier, AllowCreate = true, AllowCreateSpecified = true }, Destination = singleSignOnService.Location.ToString(), ProtocolBinding = singleSignOnService.Binding.ToString(), IssueInstant = DateTime.UtcNow, AssertionConsumerServiceURL = assertionConsumerServiceUrl }; string singleSignOnUrl = options.Configuration.SingleSignOnServices.FirstOrDefault().Location; //serialize AuthnRequest to xml string string xmlTemplate = string.Empty; XmlSerializer xmlSerializer = new XmlSerializer(typeof(AuthnRequest)); using (MemoryStream memStm = new MemoryStream()) { xmlSerializer.Serialize(memStm, authnRequest); memStm.Position = 0; xmlTemplate = new StreamReader(memStm).ReadToEnd(); } //create xml document from string XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlTemplate); xmlDoc.PreserveWhitespace = false; string request = xmlDoc.OuterXml; var result = new StringBuilder(); result.AddMessageParameter(request, null); result.AddRelayState(request, relayState); if (options.ServiceProvider.X509Certificate2 != null) { AsymmetricAlgorithm spPrivateKey = spCertificate.PrivateKey; string hashingAlgorithm = options.Configuration.Signature.SignedInfo.SignatureMethod; // Check if the key is of a supported type. [SAMLBind] sect. 3.4.4.1 specifies this. if (!(spPrivateKey is RSA || spPrivateKey is DSA || spPrivateKey == null)) { throw new ArgumentException("Signing key must be an instance of either RSA or DSA."); } AddSignature(result, spPrivateKey, hashingAlgorithm, options.ServiceProvider.HashAlgorithm); } return($"{singleSignOnUrl}?{result}"); }
public void Deserialize(string samlResponse) { ResponseType response = new ResponseType(); try { using (TextReader sr = new StringReader(samlResponse)) { var serializer = new System.Xml.Serialization.XmlSerializer(typeof(ResponseType)); response = (ResponseType)serializer.Deserialize(sr); this.Version = response.Version; this.UUID = response.ID; this.SPUID = response.InResponseTo; this.Issuer = response.Issuer.Value; switch (response.Status.StatusCode.Value) { case "urn:oasis:names:tc:SAML:2.0:status:Success": this.RequestStatus = SamlRequestStatus.Success; break; case "urn:oasis:names:tc:SAML:2.0:status:Requester": this.RequestStatus = SamlRequestStatus.RequesterError; break; case "urn:oasis:names:tc:SAML:2.0:status:Responder": this.RequestStatus = SamlRequestStatus.ResponderError; break; case "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch": this.RequestStatus = SamlRequestStatus.VersionMismatchError; break; case "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed": this.RequestStatus = SamlRequestStatus.AuthnFailed; break; case "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue": this.RequestStatus = SamlRequestStatus.InvalidAttrNameOrValue; break; case "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy": this.RequestStatus = SamlRequestStatus.InvalidNameIDPolicy; break; case "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext": this.RequestStatus = SamlRequestStatus.NoAuthnContext; break; case "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP": this.RequestStatus = SamlRequestStatus.NoAvailableIDP; break; case "urn:oasis:names:tc:SAML:2.0:status:NoPassive": this.RequestStatus = SamlRequestStatus.NoPassive; break; case "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP": this.RequestStatus = SamlRequestStatus.NoSupportedIDP; break; case "urn:oasis:names:tc:SAML:2.0:status:PartialLogout": this.RequestStatus = SamlRequestStatus.PartialLogout; break; case "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded": this.RequestStatus = SamlRequestStatus.ProxyCountExceeded; break; case "urn:oasis:names:tc:SAML:2.0:status:RequestDenied": this.RequestStatus = SamlRequestStatus.RequestDenied; break; case "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported": this.RequestStatus = SamlRequestStatus.RequestUnsupported; break; case "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated": this.RequestStatus = SamlRequestStatus.RequestVersionDeprecated; break; case "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh": this.RequestStatus = SamlRequestStatus.RequestVersionTooHigh; break; case "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow": this.RequestStatus = SamlRequestStatus.RequestVersionTooLow; break; case "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized": this.RequestStatus = SamlRequestStatus.ResourceNotRecognized; break; case "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses": this.RequestStatus = SamlRequestStatus.TooManyResponses; break; case "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile": this.RequestStatus = SamlRequestStatus.UnknownAttrProfile; break; case "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal": this.RequestStatus = SamlRequestStatus.UnknownPrincipal; break; case "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding": this.RequestStatus = SamlRequestStatus.UnsupportedBinding; break; default: this.RequestStatus = SamlRequestStatus.GenericError; break; } if (this.RequestStatus == SamlRequestStatus.Success) { foreach (var item in response.Items) { if (item.GetType() == typeof(AssertionType)) { AssertionType ass = (AssertionType)item; this.SessionIdExpireDate = (ass.Conditions.NotOnOrAfter != null) ? ass.Conditions.NotOnOrAfter : DateTime.Now.AddMinutes(20); foreach (var subitem in ass.Subject.Items) { if (subitem.GetType() == typeof(NameIDType)) { NameIDType nameId = (NameIDType)subitem; this.SubjectNameId = nameId.Value; //.Replace("SPID-",""); } } foreach (var assItem in ass.Items) { if (assItem.GetType() == typeof(AuthnStatementType)) { AuthnStatementType authnStatement = (AuthnStatementType)assItem; this.SessionId = authnStatement.SessionIndex; this.SessionIdExpireDate = (authnStatement.SessionNotOnOrAfterSpecified) ? authnStatement.SessionNotOnOrAfter : this.SessionIdExpireDate; } if (assItem.GetType() == typeof(AttributeStatementType)) { AttributeStatementType statement = (AttributeStatementType)assItem; foreach (AttributeType attribute in statement.Items) { switch (attribute.Name) { case "spidCode": this.User.SpidCode = attribute.AttributeValue[0].ToString(); break; case "name": this.User.Name = attribute.AttributeValue[0].ToString(); break; case "familyName": this.User.FamilyName = attribute.AttributeValue[0].ToString(); break; case "gender": this.User.Gender = attribute.AttributeValue[0].ToString(); break; case "ivaCode": this.User.IvaCode = attribute.AttributeValue[0].ToString(); break; case "companyName": this.User.CompanyName = attribute.AttributeValue[0].ToString(); break; case "mobilePhone": this.User.MobilePhone = attribute.AttributeValue[0].ToString(); break; case "address": this.User.Address = attribute.AttributeValue[0].ToString(); break; case "fiscalNumber": this.User.FiscalNumber = attribute.AttributeValue[0].ToString(); break; case "dateOfBirth": this.User.DateOfBirth = attribute.AttributeValue[0].ToString(); break; case "placeOfBirth": this.User.PlaceOfBirth = attribute.AttributeValue[0].ToString(); break; case "countyOfBirth": this.User.CountyOfBirth = attribute.AttributeValue[0].ToString(); break; case "idCard": this.User.IdCard = attribute.AttributeValue[0].ToString(); break; case "registeredOffice": this.User.RegisteredOffice = attribute.AttributeValue[0].ToString(); break; case "email": this.User.Email = attribute.AttributeValue[0].ToString(); break; case "expirationDate": this.User.ExpirationDate = attribute.AttributeValue[0].ToString(); break; case "digitalAddress": this.User.DigitalAddress = attribute.AttributeValue[0].ToString(); break; default: break; } } } } } } } } } catch (Exception ex) { //TODO Log throw ex; } }
/// <summary> /// GetPostSamlResponse - Returns a Base64 Encoded String with the SamlResponse in it. /// </summary> /// <param name="recipient">Recipient</param> /// <param name="issuer">Issuer</param> /// <param name="domain">Domain</param> /// <param name="subject">Subject</param> /// <param name="storeLocation">Certificate Store Location</param> /// <param name="storeName">Certificate Store Name</param> /// <param name="findType">Certificate Find Type</param> /// <param name="certLocation">Certificate Location</param> /// <param name="findValue">Certificate Find Value</param> /// <param name="certFile">Certificate File (used instead of the above Certificate Parameters)</param> /// <param name="certPassword">Certificate Password (used instead of the above Certificate Parameters)</param> /// <param name="attributes">A list of attributes to pass</param> /// <param name="signatureType">Whether to sign Response or Assertion</param> /// <returns>A base64Encoded string with a SAML response.</returns> public static string GetPostSamlResponse(string recipient, string issuer, string domain, string subject, StoreLocation storeLocation, StoreName storeName, X509FindType findType, string certFile, string certPassword, object findValue, Dictionary <string, string> attributes, SigningHelper.SignatureType signatureType) { ResponseType response = new ResponseType(); // Response Main Area response.ID = "_" + Guid.NewGuid().ToString(); response.Destination = recipient; response.Version = "2.0"; response.IssueInstant = System.DateTime.UtcNow; NameIDType issuerForResponse = new NameIDType(); issuerForResponse.Value = issuer.Trim(); response.Issuer = issuerForResponse; StatusType status = new StatusType(); status.StatusCode = new StatusCodeType(); status.StatusCode.Value = "urn:oasis:names:tc:SAML:2.0:status:Success"; response.Status = status; XmlSerializer responseSerializer = new XmlSerializer(response.GetType()); StringWriter stringWriter = new StringWriter(); XmlWriterSettings settings = new XmlWriterSettings(); settings.OmitXmlDeclaration = true; settings.Indent = true; settings.Encoding = Encoding.UTF8; XmlWriter responseWriter = XmlTextWriter.Create(stringWriter, settings); string samlString = string.Empty; AssertionType assertionType = SamlHelper.CreateSamlAssertion( issuer.Trim(), recipient.Trim(), domain.Trim(), subject.Trim(), attributes); response.Items = new AssertionType[] { assertionType }; responseSerializer.Serialize(responseWriter, response); responseWriter.Close(); samlString = stringWriter.ToString(); samlString = samlString.Replace("SubjectConfirmationData", string.Format("SubjectConfirmationData NotOnOrAfter=\"{0:o}\" Recipient=\"{1}\"", DateTime.UtcNow.AddMinutes(5), recipient)); stringWriter.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(samlString); X509Certificate2 cert = null; if (System.IO.File.Exists(certFile)) { cert = new X509Certificate2(certFile, certPassword); } else { X509Store store = new X509Store(storeName, storeLocation); store.Open(OpenFlags.ReadOnly); X509Certificate2Collection coll = store.Certificates.Find(findType, findValue, true); if (coll.Count < 1) { throw new ArgumentException("Unable to locate certificate"); } cert = coll[0]; store.Close(); } XmlElement signature = SigningHelper.SignDoc(doc, cert, "ID", (signatureType == SigningHelper.SignatureType.Response || signatureType == SigningHelper.SignatureType.TestVU475445) ? response.ID : assertionType.ID); doc.DocumentElement.InsertBefore(signature, doc.DocumentElement.ChildNodes[1]); if (SamlHelper.Logger.IsDebugEnabled) { SamlHelper.Logger.DebugFormat( "Saml Assertion before encoding = {0}", doc.OuterXml.ToString()); } string responseStr = doc.OuterXml; // 2018Ma06 Special Post-signature Maniuplation postsignature to inject comment into subject. if (signatureType == SigningHelper.SignatureType.TestVU475445) { string sub = subject.Trim(); int half = sub.Length / 2; string firstHalf = sub.Substring(0, half); string secondHalf = sub.Substring(half); responseStr = responseStr.Replace(sub, firstHalf + "<!--VU475445-->" + secondHalf); int breaker = 1; } byte[] base64EncodedBytes = Encoding.UTF8.GetBytes(responseStr); string returnValue = System.Convert.ToBase64String( base64EncodedBytes); return(returnValue); }
/// <summary> /// Creates a SAML 2.0 Assertion Segment for a Response /// Simple implmenetation assuming a list of string key and value pairs /// </summary> /// <param name="issuer"></param> /// <param name="assertionExpirationMinutes"></param> /// <param name="audience"></param> /// <param name="subject"></param> /// <param name="recipient"></param> /// <param name="attributes">Dictionary of string key, string value pairs</param> /// <returns>Assertion to sign and include in Response</returns> private static AssertionType CreateSaml20Assertion(string issuer, int assertionExpirationMinutes, string audience, string subject, string recipient, Dictionary <string, string> attributes) { AssertionType newAssertion = new AssertionType { Version = "2.0", IssueInstant = DateTime.UtcNow, ID = "_" + Guid.NewGuid(), Issuer = new NameIDType { Value = issuer.Trim() } }; // Create Issuer // Create Assertion Subject SubjectType subjectType = new SubjectType(); NameIDType subjectNameIdentifier = new NameIDType { Value = subject.Trim(), Format = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" }; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType { Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer", SubjectConfirmationData = new SubjectConfirmationDataType { NotOnOrAfter = DateTime.UtcNow.AddMinutes(assertionExpirationMinutes), Recipient = recipient } }; subjectType.Items = new object[] { subjectNameIdentifier, subjectConfirmation }; newAssertion.Subject = subjectType; // Create Assertion Conditions ConditionsType conditions = new ConditionsType { NotBefore = DateTime.UtcNow, NotBeforeSpecified = true, NotOnOrAfter = DateTime.UtcNow.AddMinutes(assertionExpirationMinutes), NotOnOrAfterSpecified = true, Items = new ConditionAbstractType[] { new AudienceRestrictionType { Audience = new[] { audience.Trim() } } } }; newAssertion.Conditions = conditions; // Add AuthnStatement and Attributes as Items AuthnStatementType authStatement = new AuthnStatementType { AuthnInstant = DateTime.UtcNow, SessionIndex = newAssertion.ID }; AuthnContextType context = new AuthnContextType { ItemsElementName = new[] { ItemsChoiceType5.AuthnContextClassRef }, Items = new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" } }; authStatement.AuthnContext = context; AttributeStatementType attributeStatement = new AttributeStatementType { Items = new object[attributes.Count] }; int i = 0; foreach (KeyValuePair <string, string> attribute in attributes) { attributeStatement.Items[i] = new AttributeType { Name = attribute.Key, AttributeValue = new object[] { attribute.Value }, NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic" }; i++; } newAssertion.Items = new StatementAbstractType[] { authStatement, attributeStatement }; return(newAssertion); }
private void CreateSAMLResponse() { FormsIdentity id = null; if (HttpContext.Current.User != null) { if (HttpContext.Current.User.Identity.IsAuthenticated) { if (HttpContext.Current.User.Identity is FormsIdentity) { id = (FormsIdentity)HttpContext.Current.User.Identity; } } } DateTime notBefore = (id != null ? id.Ticket.IssueDate.ToUniversalTime() : DateTime.UtcNow); DateTime notOnOrAfter = (id != null ? id.Ticket.Expiration.ToUniversalTime() : DateTime.UtcNow.AddMinutes(30)); IDProvider config = IDProvider.GetConfig(); SAMLResponse.Status = new StatusType(); SAMLResponse.Status.StatusCode = new StatusCodeType(); SAMLResponse.Status.StatusCode.Value = SAMLUtility.StatusCodes.Success; AssertionType assert = new AssertionType(); assert.ID = SAMLUtility.GenerateID(); assert.IssueInstant = DateTime.UtcNow.AddMinutes(10); assert.Issuer = new NameIDType(); assert.Issuer.Value = config.id; SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType(); subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer"; subjectConfirmation.SubjectConfirmationData = new SubjectConfirmationDataType(); subjectConfirmation.SubjectConfirmationData.Recipient = SAMLRequest.Issuer; subjectConfirmation.SubjectConfirmationData.InResponseTo = SAMLRequest.Request.ID; subjectConfirmation.SubjectConfirmationData.NotOnOrAfter = notOnOrAfter; NameIDType nameID = new NameIDType(); nameID.Format = SAMLUtility.NameIdentifierFormats.Transient; nameID.Value = (id != null ? id.Name : UtilBO.FormatNameFormsAuthentication(this.__SessionWEB.__UsuarioWEB.Usuario)); assert.Subject = new SubjectType(); assert.Subject.Items = new object[] { subjectConfirmation, nameID }; assert.Conditions = new ConditionsType(); assert.Conditions.NotBefore = notBefore; assert.Conditions.NotOnOrAfter = notOnOrAfter; assert.Conditions.NotBeforeSpecified = true; assert.Conditions.NotOnOrAfterSpecified = true; AudienceRestrictionType audienceRestriction = new AudienceRestrictionType(); audienceRestriction.Audience = new string[] { SAMLRequest.Issuer }; assert.Conditions.Items = new ConditionAbstractType[] { audienceRestriction }; AuthnStatementType authnStatement = new AuthnStatementType(); authnStatement.AuthnInstant = DateTime.UtcNow; authnStatement.SessionIndex = SAMLUtility.GenerateID(); authnStatement.AuthnContext = new AuthnContextType(); authnStatement.AuthnContext.Items = new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" }; authnStatement.AuthnContext.ItemsElementName = new ItemsChoiceType5[] { ItemsChoiceType5.AuthnContextClassRef }; StatementAbstractType[] statementAbstract = new StatementAbstractType[] { authnStatement }; assert.Items = statementAbstract; SAMLResponse.Items = new object[] { assert }; string xmlResponse = SAMLUtility.SerializeToXmlString(SAMLResponse); XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlResponse); XmlSignatureUtils.SignDocument(doc, assert.ID); SAMLResponse = SAMLUtility.DeserializeFromXmlString <ResponseType>(doc.InnerXml); HttpPostBinding binding = new HttpPostBinding(SAMLResponse, HttpUtility.UrlDecode(Request[HttpBindingConstants.RelayState])); binding.SendResponse(this.Context, HttpUtility.UrlDecode(SAMLRequest.AssertionConsumerServiceURL), SAMLTypeSSO.signon); }
private static void InterpretResponse(ResponseType response, EAuthResponseModel model) { model.RequestId = response.InResponseTo; // Пример за грешка: // <samlp:Status> // <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder"><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" /></samlp:StatusCode> // <samlp:StatusMessage>NOT_DETECTED_QES ***ИЛИ*** Некоректни данни</samlp:StatusMessage> // </samlp:Status> // Пример за успех: // <samlp:Status> // <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> // <samlp:StatusMessage>Успешен отговор на заявката</samlp:StatusMessage> // </samlp:Status> StatusType status = response.Status; if (status != null) { bool isSuccessful = status.StatusCode?.Value.EndsWith("Success") ?? false; string statusMessage = status.StatusMessage; // Ако в заявката към еАвт не е подаден сертификат, системата вместо съобщение за грешка връща код NOT_DETECTED_QES // ИЛИ съобщение "STS Exception: STSToken exception: bg.egov.mtits.eauthn.delegate.exceptions.STSDelegateException : null". if (statusMessage == "NOT_DETECTED_QES" || statusMessage != null && statusMessage.Contains("STSDelegateException")) { model.NotDetectedQes = true; model.Errors.Add(ClientCertNotSelected); } else if (!isSuccessful) // Съобщението за успех не се пази. { if (!string.IsNullOrEmpty(statusMessage)) { model.Errors.Add(statusMessage); } XmlElement[] details = status.StatusDetail?.Any; if (details != null) { model.Errors.AddRange(details.Select(e => e.OuterXml)); } } } if (response.Items?[0] is AssertionType assertion) { ConditionsType conditions = assertion.Conditions; if (conditions != null && conditions.NotOnOrAfterSpecified) { model.ExpirationDateTime = conditions.NotOnOrAfter; } // Пример за ЕГН: // <saml2:Subject> // <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" NameQualifier="urn:egov:bg:eauth:1.0:attributes:eIdentifier:EGN">8012311234</saml2:NameID> // <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:sender-vouches"><saml2:SubjectConfirmationData /></saml2:SubjectConfirmation> // </saml2:Subject> NameIDType nameId = assertion.Subject?.Items?.OfType <NameIDType>().FirstOrDefault(); if (nameId != null) { model.PidTypeCode = nameId.NameQualifier?.Split(':').Last(); // Към 2018-02 е известен само вид "EGN". model.PersonIdentifier = nameId.Value; } // Пример за име и контакти: // <saml2:AttributeStatement> // <saml2:Attribute Name="urn:egov:bg:eauth:1.0:attributes:personNamesLatin" NameFormat="urn:egov:bg:eauth:1.0:attributes:personNamesLatin"> // <saml2:AttributeValue xsi:type="xs:string">Ivan Dilyanov Dilov</saml2:AttributeValue> // </saml2:Attribute> // <saml2:Attribute Name="urn:egov:bg:eauth:1.0:attributes:eMail" NameFormat="urn:egov:bg:eauth:1.0:attributes:eMail"> // <saml2:AttributeValue xsi:type="xs:string">[email protected]</saml2:AttributeValue> // </saml2:Attribute> // <saml2:Attribute Name="urn:egov:bg:eauth:1.0:attributes:phone" NameFormat="urn:egov:bg:eauth:1.0:attributes:phone"> // <saml2:AttributeValue xsi:type="xs:string">+359 888476663</saml2:AttributeValue> // </saml2:Attribute> // </saml2:AttributeStatement> if (assertion.Items != null) { foreach (AttributeStatementType attributes in assertion.Items.OfType <AttributeStatementType>()) { if (attributes.Items != null) { foreach (AttributeType attribute in attributes.Items.OfType <AttributeType>()) { string type = attribute.Name?.Split(':').Last().ToLower(); string value = attribute.AttributeValue != null?string.Join(Environment.NewLine, attribute.AttributeValue.Where(v => v != null)) : null; if (type == "personnameslatin") { model.PersonNamesLatin = value; } else if (type == "email") { model.Email = value; } else if (type == "phone") { model.Phone = value; } } } } } } }