/// <summary> /// Processes the SAML response received from the IdP. /// </summary> /// <param name="page">The page object.</param> /// <param name="relayState">The relay state</param> /// <param name="samlResponse">The SAML response object.</param> public static void ProcessResponse(Page page, out ComponentPro.Saml2.Response samlResponse, out string relayState) { // Extract the binding type from the query string. string bindingType = page.Request.QueryString["binding"]; switch (bindingType) { case "artifact": // Create an artifact from the query string. Saml2ArtifactType0004 httpArtifact = Saml2ArtifactType0004.CreateFromHttpArtifactQueryString(page.Request); // Create an artifact resolve request. ArtifactResolve artifactResolve = new ArtifactResolve(); artifactResolve.Issuer = new Issuer(GetAbsoluteUrl(page, "~/")); artifactResolve.Artifact = new Artifact(httpArtifact.ToString()); // Send the artifact resolve request and create an artifact response from the received XML. ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(Global.ArtifactServiceUrl, artifactResolve); // Get the SAML Response from the artifact response. samlResponse = new ComponentPro.Saml2.Response(artifactResponse.Message); relayState = httpArtifact.RelayState; break; case "post": System.Diagnostics.Debug.WriteLine("POST"); // Create a SAML response from the form data. samlResponse = ComponentPro.Saml2.Response.Create(page.Request); relayState = samlResponse.RelayState; break; default: throw new ApplicationException("Unknown binding type"); } // Is the SAML response signed? if (samlResponse.IsSigned()) { // Get the previously loaded certificate. X509Certificate2 x509Certificate = (X509Certificate2)page.Application[Global.IdPCertKey]; // Validate the certificate. if (!samlResponse.Validate(x509Certificate)) { throw new ApplicationException("The SAML response signature failed to verify."); } } }
/// <summary> /// Processes the authentication request. /// </summary> /// <param name="authnRequest">The AuthnRequest object.</param> /// <param name="relayState">The relayState string.</param> public static void ProcessAuthnRequest(Page page, out AuthnRequest authnRequest, out string relayState) { // Use a single endpoint and use a query string parameter to determine the Service Provider to Identity Provider binding type. string bindingType = page.Request.QueryString[SP2IdPBindingTypeVar]; // Get the previously loaded certificate. X509Certificate2 cert = (X509Certificate2)page.Application[Global.SPCertKey]; switch (bindingType) { case RedirectBinding: authnRequest = AuthnRequest.Create(page.Request.RawUrl, cert.PublicKey.Key); relayState = authnRequest.RelayState; break; case PostBinding: authnRequest = AuthnRequest.CreateFromHttpPost(page.Request); relayState = authnRequest.RelayState; break; case ArtifactBinding: Saml2ArtifactType0004 httpArtifact = Saml2ArtifactType0004.CreateFromHttpArtifactHttpForm(page.Request); // Create an artifact resolve request. ArtifactResolve artifactResolve = new ArtifactResolve(); artifactResolve.Issuer = new Issuer(new Uri(page.Request.Url, page.ResolveUrl("~/")).ToString()); artifactResolve.Artifact = new Artifact(httpArtifact.ToString()); // Send the SAML Artifact Resolve Request and parse the received response. ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(Global.ArtifactResolutionUrl, artifactResolve); // Extract the authentication request from the received artifact response. authnRequest = new AuthnRequest(artifactResponse.Message); relayState = httpArtifact.RelayState; break; default: throw new ApplicationException("Invalid binding type"); } if (authnRequest.IsSigned()) { if (!authnRequest.Validate(cert)) { throw new ApplicationException("The authentication request signature failed to verify."); } } }
/// <summary> /// Receives the SAML response from the identity provider. /// </summary> /// <param name="samlResponse"></param> /// <param name="relayState"></param> private void ReceiveResponse(out ComponentPro.Saml2.Response samlResponse, out string relayState) { // Determine the identity provider to service provider binding type. // We use a query string parameter rather than having separate endpoints per binding. string bindingType = Request.QueryString[Util.BindingVarName]; switch (bindingType) { case SamlBindingUri.HttpPost: samlResponse = ComponentPro.Saml2.Response.Create(Request); relayState = samlResponse.RelayState; break; case SamlBindingUri.HttpArtifact: Saml2ArtifactType0004 httpArtifact = Saml2ArtifactType0004.CreateFromHttpArtifactHttpForm(Request); // Create an artifact resolve request. ArtifactResolve artifactResolve = new ArtifactResolve(); artifactResolve.Issuer = new Issuer(Util.GetAbsoluteUrl(this, "~/")); artifactResolve.Artifact = new Artifact(httpArtifact.ToString()); // Send the artifact resolve request and receive the artifact response. string spArtifactResponderUrl = WebConfigurationManager.AppSettings["ArtifactIdProviderUrl"]; ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(spArtifactResponderUrl, artifactResolve); // Extract the authentication request from the artifact response. samlResponse = new Response(artifactResponse.Message); relayState = httpArtifact.RelayState; break; default: Trace.Write("ServiceProvider", "Invalid identity provider to service provider binding"); samlResponse = null; relayState = null; return; } // Verify the response's signature. X509Certificate2 x509Certificate = (X509Certificate2)Application[Global.IdPCertKey]; if (!samlResponse.Validate(x509Certificate)) { throw new System.ApplicationException("The SAML response signature failed to verify."); } }
/// <summary> /// Processes a successful SAML response and redirect to the requested URL. /// </summary> /// <param name="page">The page object.</param> /// <param name="samlResponse">The SAML response object.</param> /// <param name="relayState">The relay state.</param> public static void SamlSuccessRedirect(Page page, ComponentPro.Saml2.Response samlResponse, string relayState) { // Get the previously loaded certificate. X509Certificate2 x509Certificate = (X509Certificate2)page.Application[Global.SpCertKey]; Assertion samlAssertion; // Check assertions. if (samlResponse.GetAssertions().Count > 0) { // Extract the first assertion. samlAssertion = samlResponse.GetAssertions()[0]; } else if (samlResponse.GetEncryptedAssertions().Count > 0) { // Extract the first assertion. samlAssertion = samlResponse.GetEncryptedAssertions()[0].Decrypt(x509Certificate.PrivateKey, null); } else { throw new ApplicationException("No assertions in response"); } string userName; // Get the subject name identifier. if (samlAssertion.Subject.NameId != null) { //userName = samlAssertion.Subject.NameId.NameIdentifier; userName = samlAssertion.GetAttributeValueByFriendlyName("eduPersonPrincipalName"); System.Collections.Generic.Dictionary<string, string> dict = new System.Collections.Generic.Dictionary<string, string>(); foreach (ComponentPro.Saml2.Attribute attribute in samlAssertion.AttributeStatements[0].Attributes) { dict.Add(attribute.FriendlyName, attribute.Values[0].ToString()); System.Diagnostics.Trace.WriteLine(attribute.FriendlyName + ":" + attribute.Values[0].ToString()); } HttpContext.Current.Session.Add("samlAttributes", dict); } else if (samlAssertion.Subject.EncryptedId != null) { NameId nameId = samlAssertion.Subject.EncryptedId.Decrypt(x509Certificate.PrivateKey, null); userName = nameId.NameIdentifier; } else { throw new ApplicationException("No name in subject"); } try { string aaURL = "https://idp.testshib.org:8443/idp/profile/SAML2/SOAP/AttributeQuery"; //Testing subject NameId subje = new NameId(userName,null,null,SamlNameIdentifierFormat.Unspecified,aaURL); //Testing subject Subject subject = new Subject(new NameId(userName)); SubjectConfirmation subjectConfirmation = new SubjectConfirmation(SamlSubjectConfirmationMethod.Bearer); SubjectConfirmationData subjectConfirmationData = new SubjectConfirmationData(); subjectConfirmationData.Recipient = aaURL; subjectConfirmation.SubjectConfirmationData = subjectConfirmationData; subject.SubjectConfirmations.Add(subjectConfirmation); AttributeQuery attributeQuery = new AttributeQuery(); //attributeQuery.Subject = subject; attributeQuery.Destination = aaURL; attributeQuery.Issuer = new Issuer(Global.entityId); attributeQuery.Attributes.Add(new ComponentPro.Saml2.Attribute() { FriendlyName = "givenName" }); attributeQuery.Subject = new Subject(samlAssertion.Subject.NameId); attributeQuery.Sign(x509Certificate); System.Diagnostics.Trace.WriteLine("Trying to get attributes from AA"); System.Diagnostics.Trace.WriteLine("AA query " + attributeQuery.GetXml().OuterXml); System.Diagnostics.Trace.WriteLine("AA Subject " + attributeQuery.Subject.ToString()); ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(aaURL, attributeQuery); Response attrResponse; attrResponse = new ComponentPro.Saml2.Response(artifactResponse.Message); System.Diagnostics.Trace.WriteLine("AA reponse " + attrResponse.GetXml().OuterXml); } catch (Exception e) { System.Diagnostics.Trace.WriteLine("Execption: " + e.ToString()); //throw; } // Get the originally requested resource URL from the relay state. string resourceUrl = (string)SamlSettings.CacheProvider.Remove(relayState); if (resourceUrl == null) { throw new ApplicationException("Invalid relay state"); } // Create a login context for the asserted identity. FormsAuthentication.SetAuthCookie(userName, false); // Redirect to the originally requested resource URL. page.Response.Redirect(resourceUrl, false); }
// Receive the authentication request from the service provider. public static void ReceiveAuthnRequest(Page page, out AuthnRequest authnRequest, out string relayState) { // Determine the service provider to identity provider binding type. // We use a query string parameter rather than having separate endpoints per binding. string bindingType = page.Request.QueryString[BindingQueryParameter]; switch (bindingType) { case SamlBindingUri.HttpRedirect: X509Certificate2 x509Certificate = (X509Certificate2)page.Application[Global.SPCertKey]; authnRequest = AuthnRequest.Create(page.Request.RawUrl, x509Certificate.PublicKey.Key); relayState = authnRequest.RelayState; break; case SamlBindingUri.HttpPost: authnRequest = AuthnRequest.CreateFromHttpPost(page.Request); relayState = authnRequest.RelayState; break; case SamlBindingUri.HttpArtifact: // Receive the artifact. Saml2ArtifactType0004 httpArtifact = Saml2ArtifactType0004.CreateFromHttpArtifactQueryString(page.Request); // Create an artifact resolve request. ArtifactResolve artifactResolve = new ArtifactResolve(); artifactResolve.Issuer = new Issuer(Util.GetAbsoluteUrl(page, "~/")); artifactResolve.Artifact = new Artifact(httpArtifact.ToString()); // Look up for the appropriate artifact SP url string referer = page.Request.UrlReferrer.AbsoluteUri; int i; for (i = 0; i < Services.AllowedServiceUrls.Length; i++) { string url = Services.AllowedServiceUrls[i]; if (referer.StartsWith(url)) { break; } } if (i == Services.AllowedServiceUrls.Length) { throw new Exception("Your SP is not allowed"); } // Send the artifact resolve request and receive the artifact response. string artifactServiceProviderUrl = Services.ArtifactServiceProviderUrls[i]; ArtifactResponse artifactResponse = ArtifactResponse.SendSamlMessageReceiveAftifactResponse(artifactServiceProviderUrl, artifactResolve); // Extract the authentication request from the artifact response. authnRequest = new AuthnRequest(artifactResponse.Message); relayState = httpArtifact.RelayState; break; default: Trace.Write("IdentityProvider", "Invalid service provider to identity provider binding"); authnRequest = null; relayState = null; return; } // If using HTTP redirect the message isn't signed as the generated query string is too long for most browsers. if (bindingType != SamlBindingUri.HttpRedirect) { if (authnRequest.IsSigned()) { // Verify the request's signature. X509Certificate2 x509Certificate = (X509Certificate2)page.Application[Global.SPCertKey]; if (!authnRequest.Validate(x509Certificate)) { throw new ApplicationException("The authentication request signature failed to verify."); } } } }