Esempio n. 1
0
        private void ValidateLogoutViaPost(System.Collections.Specialized.NameValueCollection requestParams, out string message, out LogoutResponse response)
        {
            var parser = new HttpPostBindingParser(requestParams);

            logger.DebugFormat(TraceMessages.LogoutResponsePostBindingParse, parser.Message);

            response = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message);

            var idp = IdpSelectionUtil.RetrieveIDPConfiguration(response.Issuer.Value, config);

            if (idp.Metadata == null)
            {
                logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
            }

            if (!parser.IsSigned)
            {
                logger.Error(ErrorMessages.ResponseSignatureMissing);
                throw new Saml20Exception(ErrorMessages.ResponseSignatureMissing);
            }

            // signature on final message in logout
            if (!parser.CheckSignature(idp.Metadata.Keys))
            {
                logger.Error(ErrorMessages.ResponseSignatureInvalid);
                throw new Saml20Exception(ErrorMessages.ResponseSignatureInvalid);
            }

            message = parser.Message;
        }
Esempio n. 2
0
        /// <summary>
        /// Handle the authentication response from the IDP.
        /// </summary>
        /// <param name="context">The context.</param>
        private void HandleResponse(HttpContext context, Saml2Configuration config)
        {
            var defaultEncoding = Encoding.UTF8;
            var doc             = GetDecodedSamlResponse(context, defaultEncoding);

            Logger.DebugFormat(TraceMessages.SamlResponseReceived, doc.OuterXml);

            // Determine whether the assertion should be decrypted before being validated.
            bool isEncrypted;
            var  assertion = GetAssertion(doc.DocumentElement, out isEncrypted);

            if (isEncrypted)
            {
                assertion = GetDecryptedAssertion(assertion, config).Assertion.DocumentElement;
            }

            // Check if an encoding-override exists for the IdP endpoint in question
            var issuer   = GetIssuer(assertion);
            var endpoint = IdpSelectionUtil.RetrieveIDPConfiguration(issuer, config);

            if (!endpoint.AllowReplayAttacks)
            {
                CheckReplayAttack(context, doc.DocumentElement, !endpoint.AllowIdPInitiatedSso);
            }
            var status = GetStatusElement(doc.DocumentElement);

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                if (status.StatusCode.Value == Saml20Constants.StatusCodes.NoPassive)
                {
                    Logger.Error(ErrorMessages.ResponseStatusIsNoPassive);
                    throw new Saml20Exception(ErrorMessages.ResponseStatusIsNoPassive);
                }

                Logger.ErrorFormat(ErrorMessages.ResponseStatusNotSuccessful, status);
                throw new Saml20Exception(string.Format(ErrorMessages.ResponseStatusNotSuccessful, status));
            }

            if (!string.IsNullOrEmpty(endpoint.ResponseEncoding))
            {
                Encoding encodingOverride;
                try
                {
                    encodingOverride = Encoding.GetEncoding(endpoint.ResponseEncoding);
                }
                catch (ArgumentException ex)
                {
                    Logger.ErrorFormat(ErrorMessages.UnknownEncoding, endpoint.ResponseEncoding);
                    throw new ArgumentException(string.Format(ErrorMessages.UnknownEncoding, endpoint.ResponseEncoding), ex);
                }

                if (encodingOverride.CodePage != defaultEncoding.CodePage)
                {
                    var doc1 = GetDecodedSamlResponse(context, encodingOverride);
                    assertion = GetAssertion(doc1.DocumentElement, out isEncrypted);
                }
            }

            HandleAssertion(context, assertion, config);
        }
Esempio n. 3
0
        /// <summary>
        /// Handle the authentication response from the IDP.
        /// </summary>
        /// <param name="context">The context.</param>
        public static Saml20Assertion HandleResponse(Saml2Configuration config, string samlResponse, IDictionary <string, object> session, Func <string, object> getFromCache, Action <string, object, DateTime> setInCache)
        {
            var defaultEncoding = Encoding.UTF8;
            var doc             = Utility.GetDecodedSamlResponse(samlResponse, defaultEncoding);

            logger.DebugFormat(TraceMessages.SamlResponseReceived, doc.OuterXml);

            // Determine whether the assertion should be decrypted before being validated.
            bool isEncrypted;
            var  assertion = Utility.GetAssertion(doc.DocumentElement, out isEncrypted);

            if (isEncrypted)
            {
                assertion = Utility.GetDecryptedAssertion(assertion, config).Assertion.DocumentElement;
            }

            // Check if an encoding-override exists for the IdP endpoint in question
            var issuer   = Utility.GetIssuer(assertion);
            var endpoint = IdpSelectionUtil.RetrieveIDPConfiguration(issuer, config);

            if (!endpoint.AllowReplayAttacks)
            {
                Utility.CheckReplayAttack(doc.DocumentElement, !endpoint.AllowIdPInitiatedSso, session);
            }
            var status = Utility.GetStatusElement(doc.DocumentElement);

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                if (status.StatusCode.Value == Saml20Constants.StatusCodes.NoPassive)
                {
                    logger.Error(ErrorMessages.ResponseStatusIsNoPassive);
                    throw new Saml20Exception(ErrorMessages.ResponseStatusIsNoPassive);
                }

                logger.ErrorFormat(ErrorMessages.ResponseStatusNotSuccessful, status);
                throw new Saml20Exception(string.Format(ErrorMessages.ResponseStatusNotSuccessful, status));
            }

            if (!string.IsNullOrEmpty(endpoint.ResponseEncoding))
            {
                Encoding encodingOverride;
                try
                {
                    encodingOverride = Encoding.GetEncoding(endpoint.ResponseEncoding);
                }
                catch (ArgumentException ex)
                {
                    logger.ErrorFormat(ErrorMessages.UnknownEncoding, endpoint.ResponseEncoding);
                    throw new ArgumentException(string.Format(ErrorMessages.UnknownEncoding, endpoint.ResponseEncoding), ex);
                }

                if (encodingOverride.CodePage != defaultEncoding.CodePage)
                {
                    var doc1 = GetDecodedSamlResponse(samlResponse, encodingOverride);
                    assertion = GetAssertion(doc1.DocumentElement, out isEncrypted);
                }
            }

            return(HandleAssertion(assertion, config, getFromCache, setInCache));
        }
Esempio n. 4
0
        /// <summary>
        /// Send an authentication request to the IDP.
        /// </summary>
        /// <param name="context">The context.</param>
        private void SendRequest(HttpContext context, Saml2Configuration config)
        {
            // See if the "ReturnUrl" - parameter is set.
            var returnUrl = context.Request.QueryString["ReturnUrl"];

            if (!string.IsNullOrEmpty(returnUrl) && context.Session != null)
            {
                context.Session["RedirectUrl"] = returnUrl;
            }

            var isRedirected  = false;
            var selectionUtil = new IdpSelectionUtil(Logger);
            var idp           = selectionUtil.RetrieveIDP(context.Request.Params, context.Request.QueryString, config, s => { context.Response.Redirect(s); isRedirected = true; });

            if (isRedirected)
            {
                return;
            }
            if (idp == null)
            {
                // Display a page to the user where she can pick the IDP
                Logger.DebugFormat(TraceMessages.IdentityProviderRedirect);

                var page = new SelectSaml20IDP();
                page.ProcessRequest(context);
                return;
            }

            var authnRequest = Saml20AuthnRequest.GetDefault(config);

            TransferClient(idp, authnRequest, context, config);
        }
Esempio n. 5
0
        private string LogoutRequestForIdp(IdentityProvider identityProvider, Saml20LogoutRequest request, IOwinContext context, Saml2Configuration config)
        {
            var logger = SAML2.Logging.LoggerProvider.LoggerFor(typeof(SamlMessage));

            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultLogoutEndpoint, identityProvider.Metadata.IDPSLOEndpoints);

            request.Destination = destination.Url;

            if (destination.Binding == BindingType.Redirect)
            {
                // do not set the Reason for DigiD
                //request.Reason = Saml20Constants.Reasons.User;
                context.Set(IdpTempSessionKey, identityProvider.Id);

                var identity = context.Request.User.Identity as ClaimsIdentity;
                var nameId   = identity.Claims.Single(c => c.Type == ClaimTypes.NameID).Value;
                request.SubjectToLogOut.Value = nameId;

                var builder = new HttpRedirectBindingBuilder
                {
                    Request    = request.GetXml().OuterXml,
                    SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey
                };

                var redirectUrl = destination.Url + (destination.Url.Contains("?") ? "&" : "?") + builder.ToQuery();
                logger.DebugFormat(TraceMessages.LogoutRequestSent, identityProvider.Id, "REDIRECT", redirectUrl);

                return(redirectUrl);
            }

            throw new NotImplementedException();
        }
Esempio n. 6
0
        public override string BuildRedirectUrl()
        {
            string rc            = null;
            var    logger        = SAML2.Logging.LoggerProvider.LoggerFor(typeof(SamlMessage));
            var    selectionUtil = new IdpSelectionUtil(logger);
            var    allparams     = BuildParams(form, context.Request.Query);
            var    idp           = selectionUtil.RetrieveIDP(allparams, BuildParams(context.Request.Query), config, s => rc = s);

            if (rc != null)
            {
                return(rc);            // IDP selection screen
            }
            if (idp == null)
            {
                // Display a page to the user where she can pick the IDP
                logger.DebugFormat(TraceMessages.IdentityProviderRedirect);
                throw new NotImplementedException("Selection of IDP not yet done (probably need a map call on middleware extension method)");
                //var page = new SelectSaml20IDP();
                //page.ProcessRequest(context);
                //return;
            }

            var authnRequest = Saml20AuthnRequest.GetDefault(config);

            return(AuthnRequestForIdp(idp, authnRequest, context, config));
        }
Esempio n. 7
0
        /// <summary>
        /// Handles the SOAP.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputStream, Saml2Configuration config, Action<Saml20Assertion> signonCallback, Func<string, object> getFromCache, Action<string, object, DateTime> setInCache, IDictionary<string, object> session)
        {
            var parser = new HttpArtifactBindingParser(inputStream);
            logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            if (parser.IsArtifactResolve) {
                logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) {
                    logger.Error(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve, ((XmlDocument)getFromCache(parser.ArtifactResolve.Artifact)).DocumentElement);
            } else if (parser.IsArtifactResponse) {
                logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) {
                    logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) {
                    logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == Response.ElementName) {
                    Utility.CheckReplayAttack(parser.ArtifactResponse.Any, true, session);

                    var responseStatus = Utility.GetStatusElement(parser.ArtifactResponse.Any);
                    if (responseStatus.StatusCode.Value != Saml20Constants.StatusCodes.Success) {
                        logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value);
                        throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value));
                    }

                    bool isEncrypted;
                    var assertion = Utility.GetAssertion(parser.ArtifactResponse.Any, out isEncrypted);
                    if (assertion == null) {
                        logger.Error(ErrorMessages.ArtifactResponseMissingAssertion);
                        throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingAssertion);
                    }

                    var samlAssertion = isEncrypted
                        ? Utility.HandleEncryptedAssertion(assertion, config, getFromCache, setInCache)
                        : Utility.HandleAssertion(assertion, config, getFromCache, setInCache);
                    signonCallback(samlAssertion);
                } else {
                    logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            } else {
                logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
        /// <summary>
        /// Handles the selection of an IDP. If only one IDP is found, the user is automatically redirected to it.
        /// If several are found, and nothing indicates to which one the user should be sent, this method returns null.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns>The <see cref="IdentityProviderElement"/>.</returns>
        public IdentityProviderElement RetrieveIDP(HttpContext context)
        {
            var config = Saml2Config.GetConfig();

            // If idpChoice is set, use it value
            if (!string.IsNullOrEmpty(context.Request.Params[IdpChoiceParameterName]))
            {
                Logger.DebugFormat(TraceMessages.IdentityProviderRetreivedFromQueryString, context.Request.Params[IdpChoiceParameterName]);
                var endPoint = config.IdentityProviders.FirstOrDefault(x => x.Id == context.Request.Params[IdpChoiceParameterName]);
                if (endPoint != null)
                {
                    return(endPoint);
                }
            }

            // If we have a common domain cookie, use it's value
            // It must have been returned from the local common domain cookie reader endpoint.
            if (!string.IsNullOrEmpty(context.Request.QueryString["_saml_idp"]))
            {
                var cdc = new CommonDomainCookie(context.Request.QueryString["_saml_idp"]);
                if (cdc.IsSet)
                {
                    var endPoint = config.IdentityProviders.FirstOrDefault(x => x.Id == cdc.PreferredIDP);
                    if (endPoint != null)
                    {
                        Logger.DebugFormat(TraceMessages.IdentityProviderRetreivedFromCommonDomainCookie, cdc.PreferredIDP);
                        return(endPoint);
                    }

                    Logger.WarnFormat(ErrorMessages.CommonDomainCookieIdentityProviderInvalid, cdc.PreferredIDP);
                }
            }

            // If there is only one configured IdentityProviderEndpointElement lets just use that
            if (config.IdentityProviders.Count == 1 && config.IdentityProviders[0].Metadata != null)
            {
                Logger.DebugFormat(TraceMessages.IdentityProviderRetreivedFromDefault, config.IdentityProviders[0].Name);
                return(config.IdentityProviders[0]);
            }

            // If one of the endpoints are marked with default, use that one
            var defaultIDP = config.IdentityProviders.FirstOrDefault(idp => idp.Default);

            if (defaultIDP != null)
            {
                Logger.DebugFormat(TraceMessages.IdentityProviderRetreivedFromDefault, defaultIDP.Id);
                return(defaultIDP);
            }

            // In case an IDP selection url has been configured, redirect to that one.
            if (!string.IsNullOrEmpty(config.IdentityProviders.SelectionUrl))
            {
                Logger.DebugFormat(TraceMessages.IdentityProviderRetreivedFromSelection, config.IdentityProviders.SelectionUrl);
                context.Response.Redirect(config.IdentityProviders.SelectionUrl);
            }

            // If an IDPSelectionEvent handler is present, request the handler for an IDP endpoint to use.
            return(IdpSelectionUtil.InvokeIDPSelectionEventHandler(config.IdentityProviders));
        }
Esempio n. 9
0
        /// <summary>
        /// Handles the SOAP message.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private async Task HandleSoap(IOwinContext context, Stream inputStream, NameValueCollection requestParams)
        {
            var config = options.Configuration;

            var parser = new HttpArtifactBindingParser(inputStream);

            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = GetBuilder(context);
            var idp     = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);

            if (parser.IsLogoutReqest)
            {
                Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml);

                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                var req = parser.LogoutRequest;

                var logoutRequestReceivedNotification = new LogoutRequestReceivedNotification <LogoutRequest, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = req
                };

                await options.Notifications.LogoutRequestReceived(logoutRequestReceivedNotification);

                DoLogout(context, true);

                // Build the response object
                var response = new Saml20LogoutResponse
                {
                    Issuer       = config.ServiceProvider.Id,
                    StatusCode   = Saml20Constants.StatusCodes.Success,
                    InResponseTo = req.Id
                };

                // response.Destination = destination.Url;
                var doc = response.GetXml();
                XmlSignatureUtils.SignDocument(doc, response.Id, config.ServiceProvider.SigningCertificate);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                SendResponseMessage(doc.OuterXml, context);
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Deserializes an assertion, verifies its signature and logs in the user if the assertion is valid.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="elem">The elem.</param>
        public static Saml20Assertion HandleAssertion(XmlElement elem, Saml2Configuration config, Func <string, object> getFromCache, Action <string, object, DateTime> setInCache)
        {
            logger.DebugFormat(TraceMessages.AssertionProcessing, elem.OuterXml);

            var issuer = GetIssuer(elem);
            var endp   = IdpSelectionUtil.RetrieveIDPConfiguration(issuer, config);

            PreHandleAssertion(elem, endp);

            if (endp == null || endp.Metadata == null)
            {
                logger.Error(ErrorMessages.AssertionIdentityProviderUnknown);
                throw new Saml20Exception(ErrorMessages.AssertionIdentityProviderUnknown);
            }

            var quirksMode = endp.QuirksMode;
            var assertion  = new Saml20Assertion(elem, null, quirksMode, config);

            // Check signatures
            if (!endp.OmitAssertionSignatureCheck)
            {
                var keys = endp.Metadata.GetKeys(KeyTypes.Signing);
                if (keys == null || !keys.Any())
                {
                    keys = endp.Metadata.GetKeys(KeyTypes.Encryption);
                }
                var trusted = GetTrustedSigners(keys, endp);
                if (!assertion.CheckSignature(trusted))
                {
                    logger.Error(ErrorMessages.AssertionSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.AssertionSignatureInvalid);
                }
            }

            // Check expiration
            if (assertion.IsExpired)
            {
                logger.Error(ErrorMessages.AssertionExpired);
                throw new Saml20Exception(ErrorMessages.AssertionExpired);
            }

            // Check one time use
            if (assertion.IsOneTimeUse)
            {
                if (getFromCache(assertion.Id) != null)
                {
                    logger.Error(ErrorMessages.AssertionOneTimeUseExceeded);
                    throw new Saml20Exception(ErrorMessages.AssertionOneTimeUseExceeded);
                }

                setInCache(assertion.Id, string.Empty, assertion.NotOnOrAfter);
            }

            logger.DebugFormat(TraceMessages.AssertionParsed, assertion.Id);
            return(assertion);
        }
Esempio n. 11
0
        private static IdentityProviderEndpoint ConfigureRequest(IdentityProvider identityProvider, Saml20AuthnRequest request, HttpContext context)
        {
            // Set the last IDP we attempted to login at.
            if (context.Session != null)
            {
                context.Session[IdpTempSessionKey] = identityProvider.Id;
            }
            context.Items[IdpTempSessionKey] = identityProvider.Id;

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultSignOnEndpoint, identityProvider.Metadata.SSOEndpoints);

            request.Destination = destination.Url;

            if (identityProvider.ForceAuth)
            {
                request.ForceAuthn = true;
            }

            // Check isPassive status
            var isPassiveFlag = context.Session != null ? context.Session[IdpIsPassive] : null;

            if (isPassiveFlag != null && (bool)isPassiveFlag)
            {
                request.IsPassive             = true;
                context.Session[IdpIsPassive] = null;
            }

            if (identityProvider.IsPassive)
            {
                request.IsPassive = true;
            }

            // Check if request should forceAuthn
            var forceAuthnFlag = context.Session != null ? context.Session[IdpForceAuthn] : null;

            if (forceAuthnFlag != null && (bool)forceAuthnFlag)
            {
                request.ForceAuthn             = true;
                context.Session[IdpForceAuthn] = null;
            }

            // Check if protocol binding should be forced
            if (identityProvider.Endpoints.DefaultSignOnEndpoint != null)
            {
                if (!string.IsNullOrEmpty(identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding;
                }
            }

            Utility.AddExpectedResponse(request, SessionToDictionary(context.Session));

            return(destination);
        }
Esempio n. 12
0
        /// <summary>
        /// Deserializes an assertion, verifies its signature and logs in the user if the assertion is valid.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="elem">The elem.</param>
        private void HandleAssertion(HttpContext context, XmlElement elem, Saml2Configuration config)
        {
            Logger.DebugFormat(TraceMessages.AssertionProcessing, elem.OuterXml);

            var issuer = GetIssuer(elem);
            var endp   = IdpSelectionUtil.RetrieveIDPConfiguration(issuer, config);

            PreHandleAssertion(context, elem, endp);

            if (endp == null || endp.Metadata == null)
            {
                Logger.Error(ErrorMessages.AssertionIdentityProviderUnknown);
                throw new Saml20Exception(ErrorMessages.AssertionIdentityProviderUnknown);
            }

            var quirksMode = endp.QuirksMode;
            var assertion  = new Saml20Assertion(elem, null, quirksMode, config);

            // Check signatures
            if (!endp.OmitAssertionSignatureCheck)
            {
                if (!assertion.CheckSignature(GetTrustedSigners(endp.Metadata.GetKeys(KeyTypes.Signing), endp)))
                {
                    Logger.Error(ErrorMessages.AssertionSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.AssertionSignatureInvalid);
                }
            }

            // Check expiration
            if (assertion.IsExpired)
            {
                Logger.Error(ErrorMessages.AssertionExpired);
                throw new Saml20Exception(ErrorMessages.AssertionExpired);
            }

            // Check one time use
            if (assertion.IsOneTimeUse)
            {
                if (context.Cache[assertion.Id] != null)
                {
                    Logger.Error(ErrorMessages.AssertionOneTimeUseExceeded);
                    throw new Saml20Exception(ErrorMessages.AssertionOneTimeUseExceeded);
                }

                context.Cache.Insert(assertion.Id, string.Empty, null, assertion.NotOnOrAfter, Cache.NoSlidingExpiration);
            }

            Logger.DebugFormat(TraceMessages.AssertionParsed, assertion.Id);

            DoSignOn(context, assertion, config);
        }
Esempio n. 13
0
        /// <summary>
        /// Handles a request.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Handle(HttpContext context, Saml2Configuration config)
        {
            Logger.Debug(TraceMessages.LogoutHandlerCalled);

            // Some IDP's are known to fail to set an actual value in the SOAPAction header
            // so we just check for the existence of the header field.
            if (Array.Exists(context.Request.Headers.AllKeys, s => s == SoapConstants.SoapAction))
            {
                HandleSoap(context, context.Request.InputStream, config);
                return;
            }

            if (!string.IsNullOrEmpty(context.Request.Params["SAMLart"]))
            {
                HandleArtifact(context, ConfigurationFactory.Instance.Configuration, HandleSoap);
                return;
            }

            if (!string.IsNullOrEmpty(context.Request.Params["SAMLResponse"]))
            {
                HandleResponse(context, config);
            }
            else if (!string.IsNullOrEmpty(context.Request.Params["SAMLRequest"]))
            {
                HandleRequest(context);
            }
            else
            {
                IdentityProvider idpEndpoint = null;

                // context.Session[IDPLoginSessionKey] may be null if IIS has been restarted
                if (context.Session[IdpSessionIdKey] != null)
                {
                    idpEndpoint = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], config);
                }

                if (idpEndpoint == null)
                {
                    // TODO: Reconsider how to accomplish this.
                    context.User = null;
                    FormsAuthentication.SignOut();

                    Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, string.Empty);
                    throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, string.Empty));
                }

                TransferClient(idpEndpoint, context, config);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            TitleText  = Resources.PageIdentityProviderSelectTitle;
            HeaderText = Resources.PageIdentityProviderSelectTitle;

            BodyPanel.Controls.Add(new LiteralControl(Resources.PageIdentityProviderSelectDescription));
            BodyPanel.Controls.Add(new LiteralControl("<br/><br/>"));

            var config = ConfigurationFactory.Instance.Configuration;

            foreach (var endPoint in config.IdentityProviders)
            {
                if (endPoint.Metadata != null)
                {
                    var link = new HyperLink
                    {
                        Text =
                            string.IsNullOrEmpty(endPoint.Name)
                                               ? endPoint.Metadata.EntityId
                                               : endPoint.Name,
                        NavigateUrl = IdpSelectionUtil.GetIdpLoginUrl(endPoint.Id, ConfigurationFactory.Instance.Configuration)
                    };

                    // Link text. If a name has been specified in web.config, use it. Otherwise, use id from metadata.
                    BodyPanel.Controls.Add(link);
                    BodyPanel.Controls.Add(new LiteralControl("<br/>"));
                }
                else
                {
                    var label = new Label {
                        Text = endPoint.Name
                    };
                    label.Style.Add(HtmlTextWriterStyle.TextDecoration, "line-through");
                    BodyPanel.Controls.Add(label);

                    label = new Label {
                        Text = " (Metadata not found)"
                    };
                    label.Style.Add(HtmlTextWriterStyle.FontSize, "x-small");
                    BodyPanel.Controls.Add(label);

                    BodyPanel.Controls.Add(new LiteralControl("<br/>"));
                }
            }
        }
Esempio n. 15
0
        public string BuildSignOutRedirectUrl()
        {
            string rc            = null;
            var    logger        = SAML2.Logging.LoggerProvider.LoggerFor(typeof(SamlMessage));
            var    selectionUtil = new IdpSelectionUtil(logger);
            var    allparams     = BuildParams(form, context.Request.Query);
            var    idp           = selectionUtil.RetrieveIDP(allparams, BuildParams(context.Request.Query), config, s => rc = s);

            if (rc != null)
            {
                return(rc);            // IDP selection screen
            }
            if (idp == null)
            {
                logger.DebugFormat(TraceMessages.IdentityProviderRedirect);
                throw new NotImplementedException("Selection of IDP not yet done (probably need a map call on middleware extension method)");
            }

            var logoutRequest = Saml20LogoutRequest.GetDefault(config);

            return(LogoutRequestForIdp(idp, logoutRequest, context, config));
        }
Esempio n. 16
0
        private void ValidateLogoutViaGet(Uri requestUrl, out string message, out LogoutResponse response)
        {
            var parser = new HttpRedirectBindingParser(requestUrl);

            response = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message);

            logger.DebugFormat(TraceMessages.LogoutResponseRedirectBindingParse, parser.Message, parser.SignatureAlgorithm, parser.Signature);

            var idp = IdpSelectionUtil.RetrieveIDPConfiguration(response.Issuer.Value, config);

            if (idp.Metadata == null)
            {
                logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
            }

            if (!parser.VerifySignature(idp.Metadata.Keys))
            {
                logger.Error(ErrorMessages.ResponseSignatureInvalid);
                throw new Saml20Exception(ErrorMessages.ResponseSignatureInvalid);
            }

            message = parser.Message;
        }
Esempio n. 17
0
        private string AuthnRequestForIdp(IdentityProvider identityProvider, Saml20AuthnRequest request, IOwinContext context, Saml2Configuration config)
        {
            var logger = SAML2.Logging.LoggerProvider.LoggerFor(typeof(SamlMessage));

            context.Set(IdpTempSessionKey, identityProvider.Id);

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultSignOnEndpoint, identityProvider.Metadata.SSOEndpoints);

            request.Destination = destination.Url;

            if (identityProvider.ForceAuth)
            {
                request.ForceAuthn = true;
            }

            // Check isPassive status
            if (context.Get <bool>(IdpIsPassive))
            {
                request.IsPassive = true;
            }

            if (identityProvider.IsPassive)
            {
                request.IsPassive = true;
            }

            // Check if request should forceAuthn
            if (context.Get <bool>(IdpForceAuthn))
            {
                request.ForceAuthn = true;
            }

            // Check if protocol binding should be forced
            if (identityProvider.Endpoints.DefaultSignOnEndpoint != null)
            {
                if (!string.IsNullOrEmpty(identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding;
                }
            }

            // Save request message id to session
            Utility.AddExpectedResponseId(request.Id);

            switch (destination.Binding)
            {
            case BindingType.Redirect:
                logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect);

                var redirectBuilder = new HttpRedirectBindingBuilder
                {
                    SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey,
                    Request    = request.GetXml().OuterXml
                };
                if (context.Authentication != null &&
                    context.Authentication.AuthenticationResponseChallenge != null &&
                    context.Authentication.AuthenticationResponseChallenge.Properties != null &&
                    context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary != null &&
                    context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.Count > 0)
                {
                    redirectBuilder.RelayState = context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary.ToDelimitedString();
                }
                logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request);

                var redirectLocation = request.Destination + (request.Destination.Contains("?") ? "&" : "?") + redirectBuilder.ToQuery();
                return(redirectLocation);

            case BindingType.Post:
            case BindingType.PostSimpleSign:
                throw new NotImplementedException();
            //logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost);

            //var postBuilder = new HttpPostBindingBuilder(destination);

            //// Honor the ForceProtocolBinding and only set this if it's not already set
            //if (string.IsNullOrEmpty(request.ProtocolBinding)) {
            //    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
            //}

            //var requestXml = request.GetXml();
            //XmlSignatureUtils.SignDocument(requestXml, request.Id, config.ServiceProvider.SigningCertificate);
            //postBuilder.Request = requestXml.OuterXml;

            //logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request);

            //context.Response.Write(postBuilder.GetPage());
            //break;
            case BindingType.Artifact:
                throw new NotImplementedException();
            //logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact);

            //var artifactBuilder = new HttpArtifactBindingBuilder(context, config);

            //// Honor the ForceProtocolBinding and only set this if it's not already set
            //if (string.IsNullOrEmpty(request.ProtocolBinding)) {
            //    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact;
            //}

            //logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml);

            //artifactBuilder.RedirectFromLogin(destination, request);
            //break;
            default:
                logger.Error(SAML2.ErrorMessages.EndpointBindingInvalid);
                throw new Saml20Exception(SAML2.ErrorMessages.EndpointBindingInvalid);
            }
            throw new NotImplementedException();
        }
Esempio n. 18
0
        /// <summary>
        /// Transfers the client.
        /// </summary>
        /// <param name="identityProvider">The identity provider.</param>
        /// <param name="request">The request.</param>
        /// <param name="context">The context.</param>
        private void TransferClient(IdentityProvider identityProvider, Saml20AuthnRequest request, HttpContext context, Saml2Configuration config)
        {
            // Set the last IDP we attempted to login at.
            if (context.Session != null)
            {
                context.Session[IdpTempSessionKey] = identityProvider.Id;
            }
            context.Items[IdpTempSessionKey] = identityProvider.Id;

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.DefaultSignOnEndpoint, identityProvider.Metadata.SSOEndpoints);

            request.Destination = destination.Url;

            if (identityProvider.ForceAuth)
            {
                request.ForceAuthn = true;
            }

            // Check isPassive status
            var isPassiveFlag = context.Session != null ? context.Session[IdpIsPassive] : null;

            if (isPassiveFlag != null && (bool)isPassiveFlag)
            {
                request.IsPassive             = true;
                context.Session[IdpIsPassive] = null;
            }

            if (identityProvider.IsPassive)
            {
                request.IsPassive = true;
            }

            // Check if request should forceAuthn
            var forceAuthnFlag = context.Session != null ? context.Session[IdpForceAuthn] : null;

            if (forceAuthnFlag != null && (bool)forceAuthnFlag)
            {
                request.ForceAuthn             = true;
                context.Session[IdpForceAuthn] = null;
            }

            // Check if protocol binding should be forced
            if (identityProvider.Endpoints.DefaultSignOnEndpoint != null)
            {
                if (!string.IsNullOrEmpty(identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = identityProvider.Endpoints.DefaultSignOnEndpoint.ForceProtocolBinding;
                }
            }

            // Save request message id to session
            if (context.Session != null)
            {
                context.Session.Add(ExpectedInResponseToSessionKey, request.Id);
            }
            else
            {
                ExpectedResponses.Add(request.Id);
            }

            switch (destination.Binding)
            {
            case BindingType.Redirect:
                Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect);

                var redirectBuilder = new HttpRedirectBindingBuilder
                {
                    SigningKey = _certificate.PrivateKey,
                    Request    = request.GetXml().OuterXml
                };

                Logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request);

                var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery();
                context.Response.Redirect(redirectLocation, true);
                break;

            case BindingType.Post:
                Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost);

                var postBuilder = new HttpPostBindingBuilder(destination);

                // Honor the ForceProtocolBinding and only set this if it's not already set
                if (string.IsNullOrEmpty(request.ProtocolBinding))
                {
                    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                }

                var requestXml = request.GetXml();
                XmlSignatureUtils.SignDocument(requestXml, request.Id, config.ServiceProvider.SigningCertificate);
                postBuilder.Request = requestXml.OuterXml;

                Logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request);

                context.Response.Write(postBuilder.GetPage());
                break;

            case BindingType.Artifact:
                Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact);

                var artifactBuilder = new HttpArtifactBindingBuilder(context, config);

                // Honor the ForceProtocolBinding and only set this if it's not already set
                if (string.IsNullOrEmpty(request.ProtocolBinding))
                {
                    request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact;
                }

                Logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml);

                artifactBuilder.RedirectFromLogin(destination, request);
                break;

            default:
                Logger.Error(ErrorMessages.EndpointBindingInvalid);
                throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid);
            }
        }
Esempio n. 19
0
        /// <summary>
        /// Handles the SOAP.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private void HandleSoap(HttpContext context, Stream inputStream, Saml2Configuration config)
        {
            var parser = new HttpArtifactBindingParser(inputStream);

            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = new HttpArtifactBindingBuilder(context, config);

            if (parser.IsArtifactResolve)
            {
                Logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse)
            {
                Logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == Response.ElementName)
                {
                    CheckReplayAttack(context, parser.ArtifactResponse.Any, true);

                    var responseStatus = GetStatusElement(parser.ArtifactResponse.Any);
                    if (responseStatus.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                    {
                        Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value);
                        throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value));
                    }

                    bool isEncrypted;
                    var  assertion = GetAssertion(parser.ArtifactResponse.Any, out isEncrypted);
                    if (assertion == null)
                    {
                        Logger.Error(ErrorMessages.ArtifactResponseMissingAssertion);
                        throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingAssertion);
                    }

                    if (isEncrypted)
                    {
                        HandleEncryptedAssertion(context, assertion, config);
                    }
                    else
                    {
                        HandleAssertion(context, assertion, config);
                    }
                }
                else
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
Esempio n. 20
0
        private void SendAuthNRequest(Saml2Configuration config)
        {
            _logger.LogDebug("Begin Transfer User to IDP");

            if (!config.IdentityProviders.Any())
            {
                _logger.LogError("No IdentityProviders configured");
            }

            // order signon endpoints by index and then check for default.



            var idp = (GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Post && x.Type == EndpointType.SignOn)
                       ?? GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Redirect && x.Type == EndpointType.SignOn));

            if (idp == null)
            {
                _logger.LogError("IdentityProvider configured does not have POST or Redirect binding", config.IdentityProviders.FirstOrDefault());
            }

            _logger.LogDebug($"IdentityProvider found: {idp.Binding.ToString()}");
            var authnRequest = CreateAuthNRequest(config);

            if (idp.Binding == BindingType.Post)
            {
                var post = new SAMLSilly.Bindings.HttpPostBindingBuilder(idp);

                if (string.IsNullOrEmpty(authnRequest.ProtocolBinding))
                {
                    authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                }

                var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Post, idp, config.IdentityProviders[0].Metadata.SSOEndpoints);
                authnRequest.Destination = destination.Url;

                var requestXml = authnRequest.GetXml();
                if (config.ServiceProvider.AuthNRequestsSigned)
                {
                    _logger.LogDebug("Sign AuthNRequest");
                    XmlSignatureUtils.SignDocument(requestXml, authnRequest.Id, config);
                }
                post.Request = requestXml.OuterXml;

                _httpContextAccessor.HttpContext.Response.WriteAsync(post.GetPage());
                return;
            }
            else
            {
                var redirectBuilder = new SAMLSilly.AspNetCore.BindingBuilders.HttpRedirectBindingBuilder(config);

                // if (string.IsNullOrEmpty(authnRequest.ProtocolBinding))
                // {
                authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                // }

                var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp, config.IdentityProviders[0].Metadata.SSOEndpoints);
                authnRequest.Destination = destination.Url;

                redirectBuilder.Request    = authnRequest.GetXml().OuterXml;
                redirectBuilder.SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey;

                var query = redirectBuilder.ToQuery();
                var url   = $"{idp.Url}?{query}";

                _httpContextAccessor.HttpContext.Response.Redirect(url, false);
                return;
            }


            throw new NotImplementedException();
        }
Esempio n. 21
0
        /// <summary>
        /// Transfers the client.
        /// </summary>
        /// <param name="idp">The identity provider.</param>
        /// <param name="context">The context.</param>
        private void TransferClient(IdentityProvider idp, HttpContext context, Saml2Configuration config)
        {
            var request = Saml20LogoutRequest.GetDefault(config);

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints);

            request.Destination = destination.Url;

            var nameIdFormat = (string)context.Session[IdpNameIdFormat];

            request.SubjectToLogOut.Format = nameIdFormat;

            // Handle POST binding
            if (destination.Binding == BindingType.Post)
            {
                var builder = new HttpPostBindingBuilder(destination);
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

                var requestDocument = request.GetXml();
                XmlSignatureUtils.SignDocument(requestDocument, request.Id, config);
                builder.Request = requestDocument.OuterXml;

                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "POST", builder.Request);

                context.Response.Write(builder.GetPage());
                context.Response.End();
                return;
            }

            // Handle Redirect binding
            if (destination.Binding == BindingType.Redirect)
            {
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

                var builder = new HttpRedirectBindingBuilder
                {
                    Request    = request.GetXml().OuterXml,
                    SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey
                };

                var redirectUrl = destination.Url + "?" + builder.ToQuery();
                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "REDIRECT", redirectUrl);

                context.Response.Redirect(redirectUrl, true);
                return;
            }

            // Handle Artifact binding
            if (destination.Binding == BindingType.Artifact)
            {
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "ARTIFACT", request.GetXml().OuterXml);

                var builder = GetBuilder(context);
                builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"), (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration));
            }

            Logger.Error(ErrorMessages.EndpointBindingInvalid);
            throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid);
        }
Esempio n. 22
0
        /// <summary>
        /// Handles the request.
        /// </summary>
        /// <param name="context">The context.</param>
        private void HandleRequest(HttpContext context)
        {
            Logger.DebugFormat(TraceMessages.LogoutRequestReceived);

            // Fetch the endpoint configuration
            var idp         = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], ConfigurationFactory.Instance.Configuration);
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints);

            // Fetch config object
            var config = ConfigurationFactory.Instance.Configuration;

            // Build the response object
            var response = new Saml20LogoutResponse
            {
                Issuer      = config.ServiceProvider.Id,
                Destination = destination.Url,
                StatusCode  = Saml20Constants.StatusCodes.Success
            };

            string message;

            if (context.Request.RequestType == "GET")
            {
                // HTTP Redirect binding
                var parser = new HttpRedirectBindingParser(context.Request.Url);
                Logger.DebugFormat(TraceMessages.LogoutRequestRedirectBindingParse, parser.Message, parser.SignatureAlgorithm, parser.Signature);

                var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id);
                if (endpoint == null || endpoint.Metadata == null)
                {
                    Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                    throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
                }

                var metadata = endpoint.Metadata;
                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.Signing)))
                {
                    Logger.Error(ErrorMessages.RequestSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid);
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST")
            {
                // HTTP Post binding
                var parser = new HttpPostBindingParser(context.Request.Params);
                Logger.DebugFormat(TraceMessages.LogoutRequestPostBindingParse, parser.Message);

                if (!parser.IsSigned)
                {
                    Logger.Error(ErrorMessages.RequestSignatureMissing);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureMissing);
                }

                var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id);
                if (endpoint == null || endpoint.Metadata == null)
                {
                    Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                    throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
                }

                var metadata = endpoint.Metadata;

                // Check signature
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.Signing)))
                {
                    Logger.Error(ErrorMessages.RequestSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid);
                }

                message = parser.Message;
            }
            else
            {
                // Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                Logger.ErrorFormat(ErrorMessages.UnsupportedRequestType, context.Request.RequestType);
                throw new Saml20Exception(string.Format(ErrorMessages.UnsupportedRequestType, context.Request.RequestType));
            }

            Logger.DebugFormat(TraceMessages.LogoutRequestParsed, message);

            // Log the user out locally
            DoLogout(context, true);

            var req = Serialization.DeserializeFromXmlString <LogoutRequest>(message);

            response.InResponseTo = req.Id;

            // Respond using redirect binding
            if (destination.Binding == BindingType.Redirect)
            {
                var builder = new HttpRedirectBindingBuilder
                {
                    RelayState = context.Request.Params["RelayState"],
                    Response   = response.GetXml().OuterXml,
                    SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey
                };

                Logger.DebugFormat(TraceMessages.LogoutResponseSent, builder.Response);

                context.Response.Redirect(destination.Url + "?" + builder.ToQuery(), true);
                return;
            }

            // Respond using post binding
            if (destination.Binding == BindingType.Post)
            {
                var builder = new HttpPostBindingBuilder(destination)
                {
                    Action = SamlActionType.SAMLResponse
                };

                var responseDocument = response.GetXml();

                Logger.DebugFormat(TraceMessages.LogoutResponseSent, responseDocument.OuterXml);

                XmlSignatureUtils.SignDocument(responseDocument, response.Id, config);
                builder.Response   = responseDocument.OuterXml;
                builder.RelayState = context.Request.Params["RelayState"];
                context.Response.Write(builder.GetPage());
            }
        }
Esempio n. 23
0
        /// <summary>
        /// Handles the SOAP message.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private void HandleSoap(HttpContext context, Stream inputStream, Saml2Configuration config)
        {
            var parser = new HttpArtifactBindingParser(inputStream);

            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = GetBuilder(context);
            var idp     = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);

            if (parser.IsArtifactResolve)
            {
                Logger.DebugFormat(TraceMessages.ArtifactResolveReceived, parser.SamlMessage);

                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve, parser.SamlMessage);
            }
            else if (parser.IsArtifactResponse)
            {
                Logger.DebugFormat(TraceMessages.ArtifactResponseReceived, parser.SamlMessage);

                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ElementName)
                {
                    Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.ArtifactResponse.Any.OuterXml);

                    var req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.ArtifactResponse.Any.OuterXml);

                    // Send logoutresponse via artifact
                    var response = new Saml20LogoutResponse
                    {
                        Issuer       = config.ServiceProvider.Id,
                        StatusCode   = Saml20Constants.StatusCodes.Success,
                        InResponseTo = req.Id
                    };

                    var endpoint    = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], config);
                    var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, endpoint.Endpoints.DefaultLogoutEndpoint, endpoint.Metadata.IDPSLOEndpoints);

                    builder.RedirectFromLogout(destination, response, context.Request.Params["relayState"], (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration));
                }
                else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ElementName)
                {
                    DoLogout(context, false, config);
                }
                else
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            }
            else if (parser.IsLogoutReqest)
            {
                Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml);

                var req = parser.LogoutRequest;

                // Build the response object
                var response = new Saml20LogoutResponse
                {
                    Issuer       = config.ServiceProvider.Id,
                    StatusCode   = Saml20Constants.StatusCodes.Success,
                    InResponseTo = req.Id
                };

                // response.Destination = destination.Url;
                var doc = response.GetXml();
                XmlSignatureUtils.SignDocument(doc, response.Id, config);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                SendResponseMessage(doc.OuterXml, context);
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }