/// <summary> /// Initializes a new instance of the ArtifactResolve class. /// </summary> /// <param name="serviceProvider">Service Provider to issue this request</param> /// <param name="artifact">SAMLv2 Artifact</param> public ArtifactResolve(IServiceProvider serviceProvider, Artifact artifact, Saml2Utils saml2Utils) { xml = new XmlDocument(); xml.PreserveWhitespace = true; nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); Id = saml2Utils.GenerateId(); IssueInstant = saml2Utils.GenerateIssueInstant(); Issuer = serviceProvider.EntityId; Artifact = artifact; var rawXml = new StringBuilder(); rawXml.Append("<samlp:ArtifactResolve"); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" ID=\"" + Id + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + IssueInstant + "\""); rawXml.Append(">"); rawXml.Append(" <saml:Issuer>" + Issuer + "</saml:Issuer>"); rawXml.Append(" <samlp:Artifact>" + Artifact + "</samlp:Artifact>"); rawXml.Append("</samlp:ArtifactResolve>"); xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Initializes a new instance of the ArtifactResolve class. /// </summary> /// <param name="serviceProvider">Service Provider to issue this request</param> /// <param name="artifact">SAMLv2 Artifact</param> public ArtifactResolve(ServiceProvider serviceProvider, Artifact artifact) { this.xml = new XmlDocument(); this.xml.PreserveWhitespace = true; this.nsMgr = new XmlNamespaceManager(this.xml.NameTable); this.nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); this.nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); this.Id = Saml2Utils.GenerateId(); this.IssueInstant = Saml2Utils.GenerateIssueInstant(); this.Issuer = serviceProvider.EntityId; this.Artifact = artifact; StringBuilder rawXml = new StringBuilder(); rawXml.Append("<samlp:ArtifactResolve"); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" ID=\"" + this.Id + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + this.IssueInstant + "\""); rawXml.Append(">"); rawXml.Append(" <saml:Issuer>" + this.Issuer + "</saml:Issuer>"); rawXml.Append(" <samlp:Artifact>" + this.Artifact.ToString() + "</samlp:Artifact>"); rawXml.Append("</samlp:ArtifactResolve>"); this.xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Returns a string representing the configured metadata for /// this service provider. This will include key information /// as well if the metadata and extended metadata have this /// information specified. /// </summary> /// <param name="signMetadata"> /// Flag to specify if the exportable metadata should be signed. /// </param> /// <returns> /// String with runtime representation of the metadata for this /// service provider. /// </returns> public string GetExportableMetadata(bool signMetadata) { XmlDocument exportableXml = (XmlDocument)this.metadata.CloneNode(true); XmlNode entityDescriptorNode = exportableXml.SelectSingleNode("/md:EntityDescriptor", this.metadataNsMgr); if (entityDescriptorNode == null) { throw new Saml2Exception(Resources.ServiceProviderEntityDescriptorNodeNotFound); } if (signMetadata && string.IsNullOrEmpty(this.SigningCertificateAlias)) { throw new Saml2Exception(Resources.ServiceProviderCantSignMetadataWithoutCertificateAlias); } if (signMetadata) { XmlAttribute descriptorId = exportableXml.CreateAttribute("ID"); descriptorId.Value = Saml2Utils.GenerateId(); entityDescriptorNode.Attributes.Append(descriptorId); Saml2Utils.SignXml(this.SigningCertificateAlias, exportableXml, descriptorId.Value, true); } return(exportableXml.InnerXml); }
/// <summary> /// Obtain the single logout resopnse location based on the given /// binding. /// </summary> /// <param name="binding"> /// The binding (should be made into constants / types). /// </param> /// <returns> /// Service response location as defined in the metadata for the /// specified IDP and binding. /// </returns> public string GetSingleLogoutServiceResponseLocation(string binding) { var xpath = string.Format("/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleLogoutService[@Binding='{0}']", binding); return (Saml2Utils.TryGetAttributeValue(_metadata, _metadataNsMgr, xpath, "ResponseLocation") ?? Saml2Utils.TryGetAttributeValue(_metadata, _metadataNsMgr, xpath, "Location")); }
/// <summary> /// Initializes a new instance of the <see cref="FileFedletRepository"/> class. /// </summary> /// <param name="homeFolder">The folder containing the configuration files.</param> /// <param name="saml2Utils"></param> public FileFedletRepository(string homeFolder, Saml2Utils saml2Utils) { _saml2Utils = saml2Utils; if (!Directory.Exists(homeFolder)) { throw new ServiceProviderUtilityException(Resources.ServiceProviderUtilityHomeFolderNotFound); } _homeFolder = new DirectoryInfo(homeFolder); }
/// <summary> /// Obtain the single logout location based on the given binding. /// </summary> /// <param name="binding"> /// The binding (should be made into constants / types). /// </param> /// <returns> /// Service location as defined in the metadata for the specified IDP /// and binding. /// </returns> public string GetSingleLogoutServiceLocation(string binding) { var xpath = new StringBuilder(); xpath.Append("/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleLogoutService"); xpath.Append("[@Binding='"); xpath.Append(binding); xpath.Append("']"); return(Saml2Utils.TryGetAttributeValue(_metadata, _metadataNsMgr, xpath.ToString(), "Location")); }
/// <summary> /// <para> /// Returns the XmlNodeList of "Values" maintained in the service /// provider's extended metadata under the attribute named /// "spAuthncontextClassrefMapping". For example: /// </para> /// <para> /// <Attribute name="spAuthncontextClassrefMapping"> /// <Value>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport|0|default</Value> /// </Attribute> /// </para> /// </summary> /// <returns>Returns the XmlNodeList of values found in the metadata.</returns> private XmlNodeList GetAuthnContextClassRefMap() { var xpath = new StringBuilder(); xpath.Append("/mdx:EntityConfig/mdx:SPSSOConfig/mdx:Attribute"); xpath.Append("[@name='spAuthncontextClassrefMapping']/mdx:Value"); XmlNode root = Saml2Utils.RequireRootElement(_extendedMetadata); XmlNodeList nodes = root.SelectNodes(xpath.ToString(), _extendedMetadataNsMgr); return(nodes); }
/// <summary> /// Initializes a new instance of the <see cref="FileWatcherFedletRepository"/> class. /// </summary> /// <param name="homeFolder">The folder containing the configuration files.</param> /// <param name="saml2Utils">Utilities</param> public FileWatcherFedletRepository(string homeFolder, Saml2Utils saml2Utils) { _homeFolder = homeFolder; _innerRepository = new FileFedletRepository(homeFolder, saml2Utils); _fileSystemWatcher = new FileSystemWatcher(homeFolder); _timer = new Timer(ReplaceCache); _fileSystemWatcher.Changed += ClearCache; _fileSystemWatcher.Created += ClearCache; _fileSystemWatcher.Deleted += ClearCache; _fileSystemWatcher.Renamed += ClearCache; _fileSystemWatcher.EnableRaisingEvents = true; }
/// <summary> /// Obtain the assertion consumer service location based on the given binding. /// </summary> /// <param name="binding">The binding associated with the desired consumer service.</param> /// <param name="index">The index associated with the desired consumer service.</param> /// <returns>Service location as defined in the metadata for the binding, null if not found.</returns> public string GetAssertionConsumerServiceLocation(string binding, string index) { var xpath = new StringBuilder(); xpath.Append("/md:EntityDescriptor/md:SPSSODescriptor/md:AssertionConsumerService"); xpath.Append("[@Binding='"); xpath.Append(binding); xpath.Append("' and index='"); xpath.Append(index); xpath.Append("']"); return(Saml2Utils.TryGetAttributeValue(_metadata, _metadataNsMgr, xpath.ToString(), "Location")); }
/// <summary> /// Gets the preferred identity provider entity id based on the value /// found in the specified string. /// </summary> /// <param name="commonDomainCookieValue">Common Domain Cookie value.</param> /// <returns>Preferred IDP Entity ID, null if not available.</returns> public static string GetPreferredIdentityProvider(string commonDomainCookieValue) { string idpEntityId = null; if (!String.IsNullOrEmpty(commonDomainCookieValue)) { char[] separator = { ' ' }; string[] listOfIdpEntityIds = commonDomainCookieValue.Split(separator); if (listOfIdpEntityIds.Length > 0) { idpEntityId = Saml2Utils.ConvertFromBase64(listOfIdpEntityIds[listOfIdpEntityIds.Length - 1]); } } return(idpEntityId); }
/// <summary> /// Initializes a new instance of the ServiceProvider class. /// </summary> public ServiceProvider(XmlDocument metadata, XmlDocument extendedMetadata, Saml2Utils saml2Utils) { _saml2Utils = saml2Utils; try { _metadata = metadata; _metadataNsMgr = new XmlNamespaceManager(metadata.NameTable); _metadataNsMgr.AddNamespace("md", "urn:oasis:names:tc:SAML:2.0:metadata"); _extendedMetadata = extendedMetadata; _extendedMetadataNsMgr = new XmlNamespaceManager(extendedMetadata.NameTable); _extendedMetadataNsMgr.AddNamespace("mdx", "urn:sun:fm:SAML:2.0:entityconfig"); } catch (XmlException xe) { throw new ServiceProviderException(Resources.ServiceProviderXmlException, xe); } }
/// <summary> /// Initializes a new instance of the IdentityProvider class. /// </summary> public IdentityProvider(XmlDocument metadata, XmlDocument extendedMetadata, Saml2Utils saml2Utils) { try { _saml2Utils = saml2Utils; _metadata = metadata; _metadataNsMgr = new XmlNamespaceManager(_metadata.NameTable); _metadataNsMgr.AddNamespace("md", "urn:oasis:names:tc:SAML:2.0:metadata"); _metadataNsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); _extendedMetadata = extendedMetadata; _extendedMetadataNsMgr = new XmlNamespaceManager(_extendedMetadata.NameTable); _extendedMetadataNsMgr.AddNamespace("mdx", "urn:sun:fm:SAML:2.0:entityconfig"); // Load now since a) it doesn't change and b) its a // performance dog on Win 2003 64-bit. byte[] byteArray = Encoding.UTF8.GetBytes(EncodedSigningCertificate); signingCertificate = new X509Certificate2(byteArray); } catch (XmlException xe) { throw new IdentityProviderException(Resources.IdentityProviderXmlException, xe); } }
/// <summary> /// Initializes a new instance of the LogoutResponse class based on /// the complimentary logout request. /// </summary> /// <param name="identityProvider"> /// IdentityProvider of the LogoutResponse /// </param> /// <param name="serviceProvider"> /// ServiceProvider of the LogoutResponse /// </param> /// <param name="logoutRequest"> /// Logout request that requires this response /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the LogoutResponse. /// </param> public LogoutResponse( IIdentityProvider identityProvider, IServiceProvider serviceProvider, LogoutRequest logoutRequest, NameValueCollection parameters) { if (identityProvider == null) { throw new Saml2Exception(Resources.LogoutResponseIdentityProviderIsNull); } if (serviceProvider == null) { throw new Saml2Exception(Resources.LogoutResponseServiceProviderIsNull); } if (logoutRequest == null) { throw new Saml2Exception(Resources.LogoutResponseLogoutRequestIsNull); } if (parameters == null) { parameters = new NameValueCollection(); } var inResponseToValue = logoutRequest.Id; var issuerValue = serviceProvider.EntityId; var binding = parameters[Saml2Constants.Binding]; if (string.IsNullOrEmpty(binding)) { binding = Saml2Constants.HttpPostProtocolBinding; } string idpSvcResponseLocation = null; if (binding != Saml2Constants.HttpSoapProtocolBinding) { idpSvcResponseLocation = identityProvider.GetSingleLogoutServiceResponseLocation(binding); } m_xml = new XmlDocument { PreserveWhitespace = true }; m_nsMgr = new XmlNamespaceManager(m_xml.NameTable); m_nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); m_nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); var rawXml = new StringBuilder(); rawXml.Append("<samlp:LogoutResponse xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" "); rawXml.Append(" ID=\"" + Saml2Utils.GenerateId() + "\" Version=\"2.0\" "); rawXml.Append(" IssueInstant=\"" + Saml2Utils.GenerateIssueInstant() + "\" "); if (idpSvcResponseLocation != null) { rawXml.Append(" Destination=\"" + idpSvcResponseLocation + "\" "); } rawXml.Append(" InResponseTo=\"" + inResponseToValue + "\">"); rawXml.Append(" <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + issuerValue + "</saml:Issuer>"); rawXml.Append(" <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">"); rawXml.Append(" <samlp:StatusCode "); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" "); rawXml.Append(" Value=\"" + Saml2Constants.Success + "\">"); rawXml.Append(" </samlp:StatusCode>"); rawXml.Append(" </samlp:Status>"); rawXml.Append("</samlp:LogoutResponse>"); m_xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Encrypts the NameID attribute of the AttributeQuery request. /// </summary> /// <param name="certFriendlyName"> /// Friendly Name of the X509Certificate to be retrieved /// from the LocalMachine keystore and used to encrypt generated symmetric key. /// Be sure to have appropriate permissions set on the keystore. /// </param> /// <param name="xmlDoc"> /// XML document to be encrypted. /// </param> /// <param name="symmetricAlgorithmUri"> /// Symmetric algorithm uri used for encryption. /// </param> public static void EncryptAttributeQueryNameID(string certFriendlyName, string symmetricAlgorithmUri, XmlDocument xmlDoc) { if (string.IsNullOrWhiteSpace(certFriendlyName)) { throw new Saml2Exception(Resources.EncryptedXmlInvalidCertFriendlyName); } if (string.IsNullOrWhiteSpace(symmetricAlgorithmUri)) { throw new Saml2Exception(Resources.EncryptedXmlInvalidEncrAlgorithm); } if (xmlDoc == null) { throw new Saml2Exception(Resources.SignedXmlInvalidXml); } X509Certificate2 cert = FedletCertificateFactory.GetCertificateByFriendlyName(certFriendlyName); if (cert == null) { throw new Saml2Exception(Resources.EncryptedXmlCertNotFound); } XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); nsMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); nsMgr.AddNamespace("saml", Saml2Constants.NamespaceSamlAssertion); nsMgr.AddNamespace("samlp", Saml2Constants.NamespaceSamlProtocol); string xpath = "/samlp:AttributeQuery/saml:Subject/saml:NameID"; XmlNode root = xmlDoc.DocumentElement; XmlNode node = root.SelectSingleNode(xpath, nsMgr); XmlNode encryptedID = xmlDoc.CreateNode(XmlNodeType.Element, "EncryptedID", Saml2Constants.NamespaceSamlAssertion); node.ParentNode.PrependChild(encryptedID); XmlElement elementToEncrypt = (XmlElement)encryptedID.AppendChild(node.Clone()); if (elementToEncrypt == null) { throw new Saml2Exception(Resources.EncryptedXmlInvalidXml); } encryptedID.ParentNode.RemoveChild(node); SymmetricAlgorithm alg = Saml2Utils.GetAlgorithm(symmetricAlgorithmUri); if (alg == null) { throw new Saml2Exception(Resources.EncryptedXmlInvalidEncrAlgorithm); } alg.GenerateKey(); string encryptionElementID = Saml2Utils.GenerateId(); string encryptionKeyElementID = Saml2Utils.GenerateId(); EncryptedData encryptedData = new EncryptedData(); encryptedData.Type = EncryptedXml.XmlEncElementUrl; encryptedData.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES128Url); encryptedData.Id = encryptionElementID; EncryptedXml encryptedXml = new EncryptedXml(); byte[] encryptedElement = encryptedXml.EncryptData(elementToEncrypt, alg, false); encryptedData.CipherData.CipherValue = encryptedElement; encryptedData.KeyInfo = new KeyInfo(); EncryptedKey encryptedKey = new EncryptedKey(); encryptedKey.Id = encryptionKeyElementID; RSA publicKeyRSA = cert.PublicKey.Key as RSA; encryptedKey.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url); encryptedKey.CipherData = new CipherData(EncryptedXml.EncryptKey(alg.Key, publicKeyRSA, false)); encryptedData.KeyInfo.AddClause(new KeyInfoRetrievalMethod("#" + encryptionKeyElementID, "http://www.w3.org/2001/04/xmlenc#EncryptedKey")); KeyInfoName kin = new KeyInfoName(); kin.Value = cert.SubjectName.Name; encryptedKey.KeyInfo.AddClause(kin); EncryptedXml.ReplaceElement(elementToEncrypt, encryptedData, false); XmlNode importKeyNode = xmlDoc.ImportNode(encryptedKey.GetXml(), true); encryptedID.AppendChild(importKeyNode); }
/// <summary> /// Initializes a new instance of the AuthnRequest class. /// </summary> /// <param name="identityProvider"> /// IdentityProvider to receive the AuthnRequest /// </param> /// <param name="serviceProvider"> /// ServiceProvider to issue the AuthnRequest /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the AuthnRequest. /// </param> /// <param name="saml2Utils">Utilities class</param> public AuthnRequest(IIdentityProvider identityProvider, IServiceProvider serviceProvider, NameValueCollection parameters, Saml2Utils saml2Utils) { xml = new XmlDocument(); xml.PreserveWhitespace = true; nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); Id = saml2Utils.GenerateId(); IssueInstant = saml2Utils.GenerateIssueInstant(); Issuer = serviceProvider.EntityId; if (parameters != null) { AllowCreate = saml2Utils.GetBoolean(parameters[Saml2Constants.AllowCreate]); AssertionConsumerServiceIndex = parameters[Saml2Constants.AssertionConsumerServiceIndex]; Binding = parameters[Saml2Constants.Binding]; Consent = parameters[Saml2Constants.Consent]; Destination = parameters[Saml2Constants.Destination]; ForceAuthn = saml2Utils.GetBoolean(parameters[Saml2Constants.ForceAuthn]); IsPassive = saml2Utils.GetBoolean(parameters[Saml2Constants.IsPassive]); NameIDPolicyFormat = parameters[Saml2Constants.NameIDPolicyFormat]; } string assertionConsumerSvcUrl = null; if (!String.IsNullOrEmpty(Binding)) { if (!String.IsNullOrEmpty(AssertionConsumerServiceIndex)) { // find assertion consumer service location by binding and index. assertionConsumerSvcUrl = serviceProvider.GetAssertionConsumerServiceLocation(Binding, AssertionConsumerServiceIndex); } else { // find assertion consumer service location by binding only, using first found. assertionConsumerSvcUrl = serviceProvider.GetAssertionConsumerServiceLocation(Binding); } } // neither index nor binding, throw exception if (String.IsNullOrEmpty(AssertionConsumerServiceIndex) && String.IsNullOrEmpty(assertionConsumerSvcUrl)) { throw new Saml2Exception(Resources.AuthnRequestAssertionConsumerServiceNotDefined); } // If destination not specified, use SSO location by binding if (string.IsNullOrEmpty(Destination)) { Destination = identityProvider.GetSingleSignOnServiceLocation(parameters[Saml2Constants.RequestBinding]); if (string.IsNullOrEmpty(Destination)) { // default to HttpRedirect Destination = identityProvider.GetSingleSignOnServiceLocation(Saml2Constants.HttpRedirectProtocolBinding); } } // Get RequestedAuthnContext if parameters are available... RequestedAuthnContext reqAuthnContext = GetRequestedAuthnContext(serviceProvider, parameters); // Generate the XML for the AuthnRequest... var rawXml = new StringBuilder(); rawXml.Append("<samlp:AuthnRequest "); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" ID=\"" + Id + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + IssueInstant + "\""); rawXml.Append(" IsPassive=\"" + IsPassive.ToString().ToLower() + "\""); rawXml.Append(" ForceAuthn=\"" + ForceAuthn.ToString().ToLower() + "\""); if (!String.IsNullOrEmpty(Consent)) { rawXml.Append(" Consent=\"" + Consent + "\""); } if (!String.IsNullOrEmpty(Destination)) { rawXml.Append(" Destination=\"" + Destination + "\""); } if (!String.IsNullOrEmpty(assertionConsumerSvcUrl)) { rawXml.Append(" ProtocolBinding=\"" + Binding + "\""); rawXml.Append(" AssertionConsumerServiceURL=\"" + assertionConsumerSvcUrl + "\""); } else { rawXml.Append(" AssertionConsumerIndex=\"" + AssertionConsumerServiceIndex + "\""); } rawXml.Append(">"); rawXml.Append("<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + serviceProvider.EntityId + "</saml:Issuer>"); rawXml.Append("<samlp:NameIDPolicy Format=\"" + NameIDPolicyFormat + "\" AllowCreate=\"" + AllowCreate.ToString().ToLower() + "\" />"); if (reqAuthnContext != null) { rawXml.Append(reqAuthnContext.GenerateXmlString()); } rawXml.Append("</samlp:AuthnRequest>"); xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Initializes a new instance of the ServiceProviderUtility class /// using the given repository for configuration and metadata. /// </summary> /// <param name="repository">repository containing configuration and metadata.</param> /// <param name="saml2Utils">Utilities Class</param> public ServiceProviderUtility(IFedletRepository repository, Saml2Utils saml2Utils) { _repository = repository; _saml2Utils = saml2Utils; }
/// <summary> /// Obtain the single sign on location based on the given binding. /// </summary> /// <param name="binding">The binding (should be made into constants / types).</param> /// <returns>Service location as defined in the metadata for the specified IDP and binding.</returns> public string GetSingleSignOnServiceLocation(string binding) { var xpath = $"/md:EntityDescriptor/md:IDPSSODescriptor/md:SingleSignOnService[@Binding='{binding}']"; return(Saml2Utils.TryGetAttributeValue(m_metadata, m_metadataNsMgr, xpath, "Location")); }
/// <summary> /// Initializes a new instance of the LogoutRequest class. /// </summary> /// <param name="identityProvider"> /// IdentityProvider of the LogoutRequest /// </param> /// <param name="serviceProvider"> /// ServiceProvider of the LogoutRequest /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the LogoutRequest. /// </param> /// <param name="saml2Utils">Utilities Class</param> public LogoutRequest( IIdentityProvider identityProvider, IServiceProvider serviceProvider, NameValueCollection parameters, Saml2Utils saml2Utils) { try { xml = new XmlDocument(); xml.PreserveWhitespace = true; nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); string sessionIndex = null; string subjectNameId = null; string binding = null; string destination = null; if (parameters != null) { sessionIndex = parameters[Saml2Constants.SessionIndex]; subjectNameId = parameters[Saml2Constants.SubjectNameId]; binding = parameters[Saml2Constants.Binding]; destination = parameters[Saml2Constants.Destination]; } if (String.IsNullOrEmpty(sessionIndex)) { throw new Saml2Exception(Resources.LogoutRequestSessionIndexNotDefined); } else if (String.IsNullOrEmpty(subjectNameId)) { throw new Saml2Exception(Resources.LogoutRequestSubjectNameIdNotDefined); } else if (serviceProvider == null) { throw new Saml2Exception(Resources.LogoutRequestServiceProviderIsNull); } else if (identityProvider == null) { throw new Saml2Exception(Resources.LogoutRequestIdentityProviderIsNull); } if (string.IsNullOrEmpty(destination)) { destination = identityProvider.GetSingleLogoutServiceLocation(binding); if (string.IsNullOrEmpty(destination)) { // default with HttpRedirect destination = identityProvider.GetSingleLogoutServiceLocation(Saml2Constants.HttpRedirectProtocolBinding); } } var rawXml = new StringBuilder(); rawXml.Append("<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" ID=\"" + saml2Utils.GenerateId() + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + saml2Utils.GenerateIssueInstant() + "\""); if (!String.IsNullOrEmpty(destination)) { rawXml.Append(" Destination=\"" + destination + "\""); } rawXml.Append(" >"); rawXml.Append(" <saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\""); rawXml.Append(" NameQualifier=\"" + identityProvider.EntityId + "\">" + subjectNameId + "</saml:NameID> "); rawXml.Append(" <saml:SessionIndex xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + sessionIndex + "</saml:SessionIndex>"); rawXml.Append(" <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + serviceProvider.EntityId + "</saml:Issuer>"); rawXml.Append("</samlp:LogoutRequest>"); xml.LoadXml(rawXml.ToString()); } catch (ArgumentNullException ane) { throw new Saml2Exception(Resources.LogoutRequestNullArgument, ane); } catch (XmlException xe) { throw new Saml2Exception(Resources.LogoutRequestXmlException, xe); } }
/// <summary> /// Initializes a new instance of the AttributeQueryRequest class. /// </summary> /// <param name="identityProvider"> /// IdentityProvider of the AttributeQueryRequest /// </param> /// <param name="serviceProvider"> /// ServiceProvider of the AttributeQueryRequest /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the AttributeQueryRequest. /// </param> /// <param name="attributes"> /// List of SamlAttribute to query /// </param> public AttributeQueryRequest(IdentityProvider identityProvider, ServiceProvider serviceProvider, NameValueCollection parameters, List <SamlAttribute> attributes) { try { this.xml = new XmlDocument(); this.xml.PreserveWhitespace = true; this.X509SubjectName = false; this.nsMgr = new XmlNamespaceManager(this.xml.NameTable); this.nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); this.nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); this.nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); string subjectNameId = null; if (parameters != null) { subjectNameId = parameters[Saml2Constants.SubjectNameId]; this.X509SubjectName = Saml2Utils.GetBoolean(parameters[Saml2Constants.X509SubjectName]); } if (string.IsNullOrWhiteSpace(subjectNameId)) { throw new Saml2Exception(Resources.AttributeQueryRequestSubjectNameIdNotDefined); } else if (serviceProvider == null) { throw new Saml2Exception(Resources.AttributeQueryRequestServiceProviderIsNull); } else if (identityProvider == null) { throw new Saml2Exception(Resources.AttributeQueryRequestIdentityProviderIsNull); } else if (attributes == null || attributes.Count == 0) { throw new Saml2Exception(Resources.AttributeQueryRequestIsEmpty); } StringBuilder rawXml = new StringBuilder(); rawXml.Append("<samlp:AttributeQuery xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" ID=\"" + Saml2Utils.GenerateId() + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + Saml2Utils.GenerateIssueInstant() + "\">"); rawXml.Append("<saml:Issuer>" + serviceProvider.EntityId + "</saml:Issuer>"); rawXml.Append("<saml:Subject>"); rawXml.Append("<saml:NameID"); if (this.X509SubjectName) { rawXml.Append(" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName\""); } else { rawXml.Append(" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\""); } rawXml.Append(" SPNameQualifier=\"" + serviceProvider.EntityId + "\""); rawXml.Append(" NameQualifier=\"" + identityProvider.EntityId + "\">" + subjectNameId + "</saml:NameID>"); rawXml.Append("</saml:Subject>"); foreach (SamlAttribute attr in attributes) { if (attr != null) { rawXml.Append(attr.ToString()); } } rawXml.Append("</samlp:AttributeQuery>"); this.xml.LoadXml(rawXml.ToString()); } catch (ArgumentNullException ane) { throw new Saml2Exception(Resources.AttributeQueryRequestNullArgument, ane); } catch (XmlException xe) { throw new Saml2Exception(Resources.AttributeQueryRequestXmlException, xe); } }
/// <summary> /// Initializes a new instance of the LogoutResponse class based on /// the complimentary logout request. /// </summary> /// <param name="identityProvider"> /// IdentityProvider of the LogoutResponse /// </param> /// <param name="serviceProvider"> /// ServiceProvider of the LogoutResponse /// </param> /// <param name="logoutRequest"> /// Logout request that requires this response /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the LogoutResponse. /// </param> /// <param name="saml2Utils">Utilities class</param> public LogoutResponse( IIdentityProvider identityProvider, IServiceProvider serviceProvider, LogoutRequest logoutRequest, NameValueCollection parameters, Saml2Utils saml2Utils) { if (identityProvider == null) { throw new Saml2Exception(Resources.LogoutResponseIdentityProviderIsNull); } else if (serviceProvider == null) { throw new Saml2Exception(Resources.LogoutResponseServiceProviderIsNull); } else if (logoutRequest == null) { throw new Saml2Exception(Resources.LogoutResponseLogoutRequestIsNull); } if (parameters == null) { parameters = new NameValueCollection(); } string inResponseToValue = logoutRequest.Id; string issuerValue = serviceProvider.EntityId; string binding = parameters[Saml2Constants.Binding]; if (string.IsNullOrEmpty(binding)) { binding = Saml2Constants.HttpPostProtocolBinding; } string idpSvcResponseLocation = null; if (binding != Saml2Constants.HttpSoapProtocolBinding) { idpSvcResponseLocation = identityProvider.GetSingleLogoutServiceResponseLocation(binding); } xml = new XmlDocument(); xml.PreserveWhitespace = true; nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); var rawXml = new StringBuilder(); rawXml.Append("<samlp:LogoutResponse xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" "); rawXml.Append(" ID=\"" + saml2Utils.GenerateId() + "\" Version=\"2.0\" "); rawXml.Append(" IssueInstant=\"" + saml2Utils.GenerateIssueInstant() + "\" "); if (idpSvcResponseLocation != null) { rawXml.Append(" Destination=\"" + idpSvcResponseLocation + "\" "); } rawXml.Append(" InResponseTo=\"" + inResponseToValue + "\">"); rawXml.Append(" <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + issuerValue + "</saml:Issuer>"); rawXml.Append(" <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">"); rawXml.Append(" <samlp:StatusCode "); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" "); rawXml.Append(" Value=\"" + Saml2Constants.Success + "\">"); rawXml.Append(" </samlp:StatusCode>"); rawXml.Append(" </samlp:Status>"); rawXml.Append("</samlp:LogoutResponse>"); xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Initializes a new instance of the LogoutRequest class. /// </summary> /// <param name="identityProvider"> /// IdentityProvider of the LogoutRequest /// </param> /// <param name="serviceProvider"> /// ServiceProvider of the LogoutRequest /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the LogoutRequest. /// </param> public LogoutRequest( IdentityProvider identityProvider, ServiceProvider serviceProvider, NameValueCollection parameters) { try { this.xml = new XmlDocument(); this.xml.PreserveWhitespace = true; this.nsMgr = new XmlNamespaceManager(this.xml.NameTable); this.nsMgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); this.nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); this.nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); string sessionIndex = null; string subjectNameId = null; string binding = null; string destination = null; if (parameters != null) { sessionIndex = parameters[Saml2Constants.SessionIndex]; subjectNameId = parameters[Saml2Constants.SubjectNameId]; binding = parameters[Saml2Constants.Binding]; destination = parameters[Saml2Constants.Destination]; } if (String.IsNullOrEmpty(sessionIndex)) { throw new Saml2Exception(Resources.LogoutRequestSessionIndexNotDefined); } else if (String.IsNullOrEmpty(subjectNameId)) { throw new Saml2Exception(Resources.LogoutRequestSubjectNameIdNotDefined); } else if (serviceProvider == null) { throw new Saml2Exception(Resources.LogoutRequestServiceProviderIsNull); } else if (identityProvider == null) { throw new Saml2Exception(Resources.LogoutRequestIdentityProviderIsNull); } if (string.IsNullOrEmpty(destination)) { destination = identityProvider.GetSingleLogoutServiceLocation(binding); if (string.IsNullOrEmpty(destination)) { // default with HttpRedirect destination = identityProvider.GetSingleLogoutServiceLocation(Saml2Constants.HttpRedirectProtocolBinding); } } StringBuilder rawXml = new StringBuilder(); rawXml.Append("<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" ID=\"" + Saml2Utils.GenerateId() + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + Saml2Utils.GenerateIssueInstant() + "\""); if (!String.IsNullOrEmpty(destination)) { rawXml.Append(" Destination=\"" + destination + "\""); } rawXml.Append(" >"); rawXml.Append(" <saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\""); rawXml.Append(" NameQualifier=\"" + identityProvider.EntityId + "\">" + subjectNameId + "</saml:NameID> "); rawXml.Append(" <samlp:SessionIndex xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">" + sessionIndex + "</samlp:SessionIndex>"); rawXml.Append(" <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + serviceProvider.EntityId + "</saml:Issuer>"); rawXml.Append("</samlp:LogoutRequest>"); this.xml.LoadXml(rawXml.ToString()); } catch (ArgumentNullException ane) { throw new Saml2Exception(Resources.LogoutRequestNullArgument, ane); } catch (XmlException xe) { throw new Saml2Exception(Resources.LogoutRequestXmlException, xe); } }
/// <summary> /// Initializes a new instance of the AuthnRequest class. /// </summary> /// <param name="identityProvider"> /// IdentityProvider to receive the AuthnRequest /// </param> /// <param name="serviceProvider"> /// ServiceProvider to issue the AuthnRequest /// </param> /// <param name="parameters"> /// NameValueCollection of varying parameters for use in the /// construction of the AuthnRequest. /// </param> public AuthnRequest(IdentityProvider identityProvider, ServiceProvider serviceProvider, NameValueCollection parameters) { this.xml = new XmlDocument(); this.xml.PreserveWhitespace = true; this.nsMgr = new XmlNamespaceManager(this.xml.NameTable); this.nsMgr.AddNamespace("saml", "urn:oasis:names:tc:SAML:2.0:assertion"); this.nsMgr.AddNamespace("samlp", "urn:oasis:names:tc:SAML:2.0:protocol"); this.Id = Saml2Utils.GenerateId(); this.IssueInstant = Saml2Utils.GenerateIssueInstant(); this.Issuer = serviceProvider.EntityId; if (parameters != null) { this.AllowCreate = Saml2Utils.GetBoolean(parameters[Saml2Constants.AllowCreate]); this.AssertionConsumerServiceIndex = parameters[Saml2Constants.AssertionConsumerServiceIndex]; this.Binding = parameters[Saml2Constants.Binding]; this.Consent = parameters[Saml2Constants.Consent]; this.Destination = parameters[Saml2Constants.Destination]; this.ForceAuthn = Saml2Utils.GetBoolean(parameters[Saml2Constants.ForceAuthn]); this.IsPassive = Saml2Utils.GetBoolean(parameters[Saml2Constants.IsPassive]); } string assertionConsumerSvcUrl = null; if (!String.IsNullOrEmpty(this.Binding)) { if (!String.IsNullOrEmpty(this.AssertionConsumerServiceIndex)) { // find assertion consumer service location by binding and index. assertionConsumerSvcUrl = serviceProvider.GetAssertionConsumerServiceLocation(this.Binding, this.AssertionConsumerServiceIndex); } else { // find assertion consumer service location by binding only, using first found. assertionConsumerSvcUrl = serviceProvider.GetAssertionConsumerServiceLocation(this.Binding); } } // neither index nor binding, throw exception if (String.IsNullOrEmpty(this.AssertionConsumerServiceIndex) && String.IsNullOrEmpty(assertionConsumerSvcUrl)) { throw new Saml2Exception(Resources.AuthnRequestAssertionConsumerServiceNotDefined); } // If destination not specified, use SSO location by binding if (string.IsNullOrEmpty(this.Destination)) { this.Destination = identityProvider.GetSingleSignOnServiceLocation(parameters[Saml2Constants.RequestBinding]); if (string.IsNullOrEmpty(this.Destination)) { // default to HttpRedirect this.Destination = identityProvider.GetSingleSignOnServiceLocation(Saml2Constants.HttpRedirectProtocolBinding); } } // Get RequestedAuthnContext if parameters are available... RequestedAuthnContext reqAuthnContext = GetRequestedAuthnContext(serviceProvider, parameters); // Get Scoping if available... Scoping scoping = GetScoping(serviceProvider); // Generate the XML for the AuthnRequest... StringBuilder rawXml = new StringBuilder(); rawXml.Append("<samlp:AuthnRequest"); rawXml.Append(" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\""); rawXml.Append(" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\""); rawXml.Append(" ID=\"" + this.Id + "\""); rawXml.Append(" Version=\"2.0\""); rawXml.Append(" IssueInstant=\"" + this.IssueInstant + "\""); rawXml.Append(" IsPassive=\"" + (this.IsPassive ? "true" : "false") + "\""); rawXml.Append(" ForceAuthn=\"" + (this.ForceAuthn ? "true" : "false") + "\""); if (!String.IsNullOrEmpty(this.Consent)) { rawXml.Append(" Consent=\"" + this.Consent + "\""); } if (!String.IsNullOrEmpty(this.Destination)) { rawXml.Append(" Destination=\"" + this.Destination + "\""); } if (!String.IsNullOrEmpty(assertionConsumerSvcUrl)) { rawXml.Append(" ProtocolBinding=\"" + this.Binding + "\""); rawXml.Append(" AssertionConsumerServiceURL=\"" + assertionConsumerSvcUrl + "\""); } else { rawXml.Append(" AssertionConsumerIndex=\"" + this.AssertionConsumerServiceIndex + "\""); } rawXml.Append(">"); rawXml.Append("<saml:Issuer>" + serviceProvider.EntityId + "</saml:Issuer>"); rawXml.Append("<samlp:NameIDPolicy AllowCreate=\"" + (this.AllowCreate ? "true" : "false") + "\" />"); if (reqAuthnContext != null) { rawXml.Append(reqAuthnContext.GenerateXmlString()); } if (scoping != null) { rawXml.Append(scoping.GenerateXmlString()); } rawXml.Append("</samlp:AuthnRequest>"); this.xml.LoadXml(rawXml.ToString()); }
/// <summary> /// Obtain the assertion consumer service location based on the given binding. /// </summary> /// <param name="binding">The binding associated with the desired consumer service.</param> /// <param name="index">The index associated with the desired consumer service.</param> /// <returns>Service location as defined in the metadata for the binding, null if not found.</returns> public string GetAssertionConsumerServiceLocation(string binding, string index) { var xpath = $"/md:EntityDescriptor/md:SPSSODescriptor/md:AssertionConsumerService[@Binding='{binding}' and index='{index}']"; return(Saml2Utils.TryGetAttributeValue(m_metadata, m_metadataNsMgr, xpath, "Location")); }