/// <summary>
        /// SAML2 Logout.
        ///
        /// The SAML2 logout is complicated as there are two main scenarios.
        ///
        /// Scenario 1.
        ///
        /// It's this application that triggers the logout.
        /// The application sends the LogoutRequest to the server
        /// and the server is supposed to answer with the LogoutResponse,
        /// sent to this endpoint (assuming the /account/logout is
        /// registered as the logout endpoint in the IdP).
        ///
        /// In this app the LogoutRequest sending is handled in the HomeController
        /// (home/logout)
        ///
        /// Scenario 2.
        ///
        /// Another application triggers the logout. The server
        /// gets the LogoutRequest from this another app and
        /// sends LogoutRequest here. This app is supposed to
        /// answer with the LogoutResponse.
        ///
        /// Both scenarios means that to handle logouts correctly,
        /// the app has to be able to both send and receive
        /// both LogoutRequest and LogoutResponse
        /// </summary>
        public ActionResult Logout()
        {
            var sam2           = new Saml2AuthenticationModule();
            var idpCertificate = new ClientCertificateProvider().GetIdPCertificate();

            if (sam2.IsLogoutRequest(this.Request) ||
                sam2.IsLogoutResponse(this.Request)
                )
            {
                // first check if this is a LogoutResponse from the IdP
                var logoutResponse = new LogoutResponseFactory().From(this.Request);
                if (logoutResponse != null)
                {
                    var result = sam2.MessageSigner.Validate(logoutResponse, idpCertificate);
                    if (!result)
                    {
                        throw new ValidationException("The LogoutResponse is not correctly signed with the IdP certificate");
                    }
                }

                // then check if this is a LogoutRequest from the IdP
                var logoutRequest = new LogoutRequestFactory().From(this.Request);
                if (logoutRequest != null)
                {
                    var result = sam2.MessageSigner.Validate(logoutRequest, idpCertificate);
                    if (!result)
                    {
                        throw new ValidationException("The LogoutResponse is not correctly signed with the IdP certificate");
                    }
                }

                // both possibilities were validated
                // signout can be performed
                FormsAuthentication.SignOut();

                // create the response in case of the LogoutRequest
                if (logoutRequest != null)
                {
                    var assertionIssuer  = ConfigurationManager.AppSettings["AssertionIssuer"];
                    var identityProvider = ConfigurationManager.AppSettings["IdentityProvider"];

                    var x509Configuration = new X509Configuration()
                    {
                        SignatureCertificate = new ClientCertificateProvider().GetClientCertificate(),
                        IncludeKeyInfo       = true,
                        SignatureAlgorithm   = Signature.SignatureAlgorithm.SHA256
                    };

                    var requestBinding = Binding.POST;

                    var logoutResponseFactory = new LogoutResponseFactory();

                    logoutResponseFactory.Issuer      = assertionIssuer;
                    logoutResponseFactory.Destination = identityProvider;

                    logoutResponseFactory.RequestBinding    = requestBinding;
                    logoutResponseFactory.X509Configuration = x509Configuration;

                    // mark the response
                    logoutResponseFactory.InResponseTo = logoutRequest.SessionIndex;

                    switch (logoutResponseFactory.RequestBinding)
                    {
                    case Constants.Binding.POST:
                        return(Content(logoutResponseFactory.CreatePostBindingContent()));

                    default:
                        throw new ArgumentException(string.Format("The {0} logout response binding is not supported", logoutResponseFactory.RequestBinding));
                    }
                }
            }

            // go back to the main page (possibly with logout
            return(Redirect(FormsAuthentication.DefaultUrl));
        }
        /// <summary>
        /// Logon flow
        /// </summary>
        public ActionResult Logon()
        {
            var saml2 = new Saml2AuthenticationModule();

            // parameters
            var assertionConsumerServiceURL = ConfigurationManager.AppSettings["AssertionConsumerServiceURL"];
            var assertionIssuer             = ConfigurationManager.AppSettings["AssertionIssuer"];
            var identityProvider            = ConfigurationManager.AppSettings["IdentityProvider"];
            var artifactResolve             = ConfigurationManager.AppSettings["ArtifactResolve"];

            var requestBinding  = Binding.POST;
            var responseBinding = Binding.POST;

            // this is optional
            var x509Configuration = new X509Configuration()
            {
                SignatureCertificate = new ClientCertificateProvider().GetClientCertificate(),
                IncludeKeyInfo       = true,
                SignatureAlgorithm   = Signature.SignatureAlgorithm.SHA256
            };

            // check if this is
            if (!saml2.IsSignInResponse(this.Request))
            {
                // AuthnRequest factory
                var authnRequestFactory = new AuthnRequestFactory();

                authnRequestFactory.AssertionConsumerServiceURL = assertionConsumerServiceURL;
                authnRequestFactory.AssertionIssuer             = assertionIssuer;
                authnRequestFactory.Destination = identityProvider;

                authnRequestFactory.X509Configuration = x509Configuration;

                authnRequestFactory.RequestBinding  = requestBinding;
                authnRequestFactory.ResponseBinding = responseBinding;

                switch (authnRequestFactory.RequestBinding)
                {
                case Constants.Binding.REDIRECT:
                    return(Redirect(authnRequestFactory.CreateRedirectBindingContent()));

                case Constants.Binding.POST:
                    return(Content(authnRequestFactory.CreatePostBindingContent()));

                default:
                    throw new ArgumentException(string.Format("The {0} request binding is not supported", authnRequestFactory.RequestBinding));
                }
            }
            else
            {
                // the token is created from the IdP's response
                Saml2SecurityToken securityToken = null;

                switch (responseBinding)
                {
                case Binding.ARTIFACT:

                    var artifactConfig = new ArtifactResolveConfiguration()
                    {
                        ArtifactResolveUri = artifactResolve,
                        Issuer             = assertionIssuer,
                        X509Configuration  = x509Configuration
                    };

                    securityToken = saml2.GetArtifactSecurityToken(this.Request, artifactConfig);
                    break;

                case Binding.POST:
                    securityToken = saml2.GetPostSecurityToken(this.Request);
                    break;

                default:
                    throw new NotSupportedException(string.Format("The {0} response binding is not yet supported", responseBinding));
                }

                // fail if there is no token
                if (securityToken == null)
                {
                    throw new ArgumentNullException("No security token found in the response accoding to the Response Binding configuration");
                }

                // the token will be validated
                var configuration = new SecurityTokenHandlerConfiguration
                {
                    CertificateValidator = X509CertificateValidator.None,
                    IssuerNameRegistry   = new DemoClientIssuerNameRegistry(),
                    DetectReplayedTokens = false
                };
                configuration.AudienceRestriction.AudienceMode = AudienceUriMode.Never;

                var tokenHandler = new Saml2SecurityTokenHandler()
                {
                    Configuration = configuration
                };
                var identity = tokenHandler.ValidateToken(securityToken);

                // this is the SessionIndex, store it if necessary
                string sessionIndex = securityToken.Assertion.ID;

                // the token is validated succesfully
                var principal = new ClaimsPrincipal(identity);
                if (principal.Identity.IsAuthenticated)
                {
                    var formsTicket = new FormsAuthenticationTicket(
                        1, principal.Identity.Name, DateTime.UtcNow, DateTime.UtcNow.Add(FormsAuthentication.Timeout), false, sessionIndex);

                    this.Response.AppendCookie(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(formsTicket)));

                    var redirectUrl = FormsAuthentication.GetRedirectUrl(principal.Identity.Name, false);

                    return(Redirect(redirectUrl));
                }
                else
                {
                    throw new ArgumentNullException("principal", "Unauthenticated principal returned from token validation");
                }
            }
        }
        /// <summary>
        /// Trigger SAML2 SSO AuthnRequest
        /// </summary>
        /// <returns></returns>
        public ActionResult Logon()
        {
            var saml2 = new Saml2AuthenticationModule();

            // parameters
            var assertionConsumerServiceURL = ConfigurationManager.AppSettings["issuerSSO"];
            var assertionIssuer             = ConfigurationManager.AppSettings["issuerName"];
            var identityProvider            = ConfigurationManager.AppSettings["ePUAPSSO"];
            var artifactResolve             = ConfigurationManager.AppSettings["ePUAPArtifact"];

            var getTpUserInfoUri = ConfigurationManager.AppSettings["tpUserInfo"];

            var requestBinding  = Binding.POST;
            var responseBinding = Binding.ARTIFACT;

            // this is optional
            var x509Configuration = new X509Configuration()
            {
                SignatureCertificate = new ClientCertificateProvider().GetClientCertificate(),
                IncludeKeyInfo       = true,
                SignatureAlgorithm   = OldMusicBox.Saml2.Signature.SignatureAlgorithm.SHA256
            };

            // check if this is
            if (!saml2.IsSignInResponse(this.Request))
            {
                // AuthnRequest factory
                var authnRequestFactory = new AuthnRequestFactory();

                authnRequestFactory.AssertionConsumerServiceURL = assertionConsumerServiceURL;
                authnRequestFactory.AssertionIssuer             = assertionIssuer;
                authnRequestFactory.Destination = identityProvider;

                authnRequestFactory.X509Configuration = x509Configuration;

                authnRequestFactory.RequestBinding  = requestBinding;
                authnRequestFactory.ResponseBinding = responseBinding;

                return(Content(authnRequestFactory.CreatePostBindingContent()));
            }
            else
            {
                // the token is created from the IdP's response
                var artifactConfig = new ArtifactResolveConfiguration()
                {
                    ArtifactResolveUri = artifactResolve,
                    Issuer             = assertionIssuer,
                    X509Configuration  = x509Configuration
                };

                var securityToken = saml2.GetArtifactSecurityToken(this.Request, artifactConfig);

                // fail if there is no token
                if (securityToken == null ||
                    securityToken.Assertion == null ||
                    string.IsNullOrEmpty(securityToken.Assertion.ID)
                    )
                {
                    throw new ArgumentNullException("No valid security token found in the response accoding to the ARTIFACT Response Binding");
                }

                // the token will be validated
                #warning Implement token validation

                // this is the SessionIndex, store it if necessary
                var        sessionIndex = securityToken.Assertion.ID;
                var        client       = new ServiceClient(getTpUserInfoUri, x509Configuration.SignatureCertificate);
                FaultModel fault;
                var        tpUserInfo = client.GetTpUserInfo(sessionIndex, out fault);
                if (tpUserInfo == null || !tpUserInfo.IsValid)
                {
                    throw new NullReferenceException(string.Format("GetTpUserInfo returned nothing. Error message is: {0}", fault != null ? fault.FaultString : "."));
                }

                // create the identity
                var identity = new ClaimsIdentity("ePUAP");

                identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, tpUserInfo.Podpis.Dane.DaneOsobyFizycznej.IdKontaUzytkownikaEpuap));
                identity.AddClaim(new Claim(ClaimTypes.GivenName, tpUserInfo.Podpis.Dane.DaneOsobyFizycznej.Imie));
                identity.AddClaim(new Claim(ClaimTypes.Surname, tpUserInfo.Podpis.Dane.DaneOsobyFizycznej.Nazwisko.Value));
                identity.AddClaim(new Claim(OMBClaimTypes.PESEL, tpUserInfo.Podpis.Dane.DaneOsobyFizycznej.PESEL));
                identity.AddClaim(new Claim(OMBClaimTypes.SessionIndex, sessionIndex));

                if (!string.IsNullOrEmpty(tpUserInfo.Return.AccountEmailAddress))
                {
                    identity.AddClaim(new Claim(ClaimTypes.Email, tpUserInfo.Return.AccountEmailAddress));
                }

                // the token is validated succesfully
                var principal = new ClaimsPrincipal(identity);
                if (principal.Identity.IsAuthenticated)
                {
                    // use the SessionAuthenticationModule to store the auth cookie
                    var sam = FederatedAuthentication.SessionAuthenticationModule;

                    var token = sam.CreateSessionSecurityToken(principal, string.Empty,
                                                               DateTime.Now.ToUniversalTime(), DateTime.Now.AddMinutes(20).ToUniversalTime(), false);
                    sam.WriteSessionTokenToCookie(token);

                    // fixed return url because the provider redirects here without the query string
                    return(Redirect("/Home/Signed"));
                }
                else
                {
                    throw new ArgumentNullException("principal", "Unauthenticated principal returned from token validation");
                }
            }
        }