Example #1
0
        private static CommandResult HandleResponse(UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl)
        {
            var logoutResponse = Saml2LogoutResponse.FromXml(unbindResult.Data);
            var notificationHandledTheStatus = options.Notifications.ProcessSingleLogoutResponseStatus(logoutResponse, storedRequestState);

            if (!notificationHandledTheStatus)
            {
                var status = logoutResponse.Status;
                if (status != Saml2StatusCode.Success)
                {
                    throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                               "Idp returned status \"{0}\", indicating that the single logout failed. The local session has been successfully terminated.",
                                                                               status));
                }
            }

            var commandResult = new CommandResult
            {
                HttpStatusCode = HttpStatusCode.SeeOther
            };

            if (!options.SPOptions.Compatibility.DisableLogoutStateCookie)
            {
                commandResult.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState;
            }
            commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl;

            options.SPOptions.Logger.WriteInformation("Received logout response " + logoutResponse.Id
                                                      + ", redirecting to " + commandResult.Location);

            return(commandResult);
        }
Example #2
0
        private static CommandResult HandleRequest(UnbindResult unbindResult, IOptions options)
        {
            var request = Saml2LogoutRequest.FromXml(unbindResult.Data);

            var idp = options.IdentityProviders[request.Issuer];

            if (options.SPOptions.SigningServiceCertificate == null)
            {
                throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture,
                                                                     "Received a LogoutRequest from \"{0}\" but cannot reply because single logout responses must be signed and there is no signing certificate configured. Looks like the idp is configured for Single Logout despite AuthServices not exposing that functionality in the metadata.",
                                                                     request.Issuer.Id));
            }

            var response = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = idp.SingleLogoutServiceResponseUrl,
                SigningCertificate = options.SPOptions.SigningServiceCertificate,
                InResponseTo       = request.Id,
                Issuer             = options.SPOptions.EntityId,
                RelayState         = unbindResult.RelayState
            };

            var result = Saml2Binding.Get(idp.SingleLogoutServiceBinding).Bind(response);

            result.TerminateLocalSession = true;
            return(result);
        }
Example #3
0
        public ValueTask <LogoutModel> LogoutCallback(IdentityHttpRequest request)
        {
            var callbackBinding = Saml2Binding.GetBindingForRequest(request, BindingDirection.Response);

            callbackBinding.ValidateSignature(identityProviderCert, true);
            callbackBinding.ValidateFields(new string[] { redirectUrl });

            var callbackDocument = new Saml2LogoutResponse(callbackBinding);

            SamlIDManager.Validate(serviceProvider, callbackDocument.InResponseTo);

            if (String.IsNullOrWhiteSpace(callbackDocument.Issuer))
            {
                return(new ValueTask <LogoutModel>((LogoutModel)null));
            }

            var logout = new LogoutModel()
            {
                ServiceProvider = callbackDocument.Issuer,
                State           = null,
                OtherClaims     = null
            };

            return(new ValueTask <LogoutModel>(logout));
        }
Example #4
0
        private async Task <IActionResult> LogoutResponseAsync <T>(Saml2Configuration samlConfig, string inResponseTo, string relayState, string loggedOutUrl, Saml2Binding <T> binding, Saml2StatusCodes status, string sessionIndex = null)
        {
            binding.RelayState = relayState;

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig)
            {
                InResponseTo = new Saml2Id(inResponseTo),
                Status       = status,
                Destination  = new Uri(loggedOutUrl),
                SessionIndex = sessionIndex
            };

            binding.Bind(saml2LogoutResponse);
            logger.ScopeTrace($"SAML Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.");
            logger.ScopeTrace($"Logged out url '{loggedOutUrl}'.");
            logger.ScopeTrace("Down, SAML Logout response.", triggerEvent: true);

            await sequenceLogic.RemoveSequenceDataAsync <SamlDownSequenceData>();

            await formActionLogic.RemoveFormActionSequenceDataAsync();

            if (binding is Saml2Binding <Saml2RedirectBinding> )
            {
                return(await Task.FromResult((binding as Saml2RedirectBinding).ToActionResult()));
            }
            if (binding is Saml2Binding <Saml2PostBinding> )
            {
                return(await Task.FromResult((binding as Saml2PostBinding).ToActionResult()));
            }
            else
            {
                throw new NotSupportedException();
            }
        }
        public async Task <IActionResult> SingleLogout()
        {
            var loginType = await GetSelectedLoginType();

            Saml2StatusCodes status;
            var requestBinding = new Saml2PostBinding();
            var logoutRequest  = new Saml2LogoutRequest(saml2Config, User);

            try
            {
                requestBinding.Unbind(Request.ToGenericHttpRequest(), logoutRequest);
                status = Saml2StatusCodes.Success;
                await idPSelectionCookieRepository.DeleteAsync();

                await logoutRequest.DeleteSession(HttpContext);
            }
            catch (Exception exc)
            {
                // log exception
                Debug.WriteLine("SingleLogout error: " + exc.ToString());
                status = Saml2StatusCodes.RequestDenied;
            }

            var responsebinding = new Saml2PostBinding();

            responsebinding.RelayState = requestBinding.RelayState;
            var saml2LogoutResponse = new Saml2LogoutResponse(saml2Config)
            {
                InResponseToAsString = logoutRequest.IdAsString,
                Status = status,
            };

            saml2LogoutResponse.Destination = AddUpParty(saml2LogoutResponse.Destination, loginType);
            return(responsebinding.Bind(saml2LogoutResponse).ToActionResult());
        }
        public void Saml2LogoutResponse_AppendTo_AllSupported()
        {
            var subject = new Saml2LogoutResponse(Saml2StatusCode.Requester)
            {
                Issuer         = new EntityId("https://ServiceProvider.com/SAML"),
                DestinationUrl = new Uri("https://IdentityProvider.com/Logout"),
                InResponseTo   = new Saml2Id()
            };

            var expectedXml =
                $@"<samlp:LogoutResponse xmlns:samlp=""urn:oasis:names:tc:SAML:2.0:protocol""
                    xmlns=""urn:oasis:names:tc:SAML:2.0:assertion""
                    ID=""{subject.Id}""
                    InResponseTo=""{subject.InResponseTo.Value}""
                    IssueInstant=""{subject.IssueInstant.ToSaml2DateTimeString()}"" Version=""2.0""
                    Destination=""https://IdentityProvider.com/Logout"">
                    <Issuer>https://ServiceProvider.com/SAML</Issuer>
                    <samlp:Status>
                        <samlp:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Requester""/>
                    </samlp:Status>
                </samlp:LogoutResponse>";

            var expectedElement = XmlHelpers.XmlDocumentFromString(expectedXml).DocumentElement;

            var xmlDoc = XmlHelpers.CreateSafeXmlDocument();

            subject.AppendTo(xmlDoc);

            xmlDoc.DocumentElement.Should().BeEquivalentTo(expectedElement, "XML should be full LogoutResponse");
        }
Example #7
0
        private async Task <IActionResult> SingleLogoutResponseAsync <T>(SamlDownParty party, Saml2Binding <T> binding)
        {
            var samlConfig = await saml2ConfigurationLogic.GetSamlDownConfigAsync(party);

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig);

            binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
            logger.ScopeTrace(() => $"SAML Single Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);

            ValidateLogoutResponse(party, saml2LogoutResponse);
            await sequenceLogic.ValidateExternalSequenceIdAsync(binding.RelayState);

            try
            {
                binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
                logger.ScopeTrace(() => "Down, SAML Single Logout response accepted.", triggerEvent: true);
            }
            catch (Exception ex)
            {
                var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex);
                if (isex != null)
                {
                    throw isex;
                }
                throw;
            }

            return(await singleLogoutDownLogic.HandleSingleLogoutAsync());
        }
        public void LogoutCommand_Run_ThrowsOnLogoutResponseStatusNonSuccess()
        {
            var response = new Saml2LogoutResponse(Saml2StatusCode.Requester)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                SigningAlgorithm   = SecurityAlgorithms.RsaSha256Signature
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET", bindResult.Location,
                                              "http://sp-internal.example.com/path/Saml2", null, null, null);

            var options = StubFactory.CreateOptions();

            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/path/");

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(request, options))
            .Should().Throw <UnsuccessfulSamlOperationException>()
            .And.Message.Should().Be("Idp returned status \"Requester\", indicating that the single logout failed. The local session has been successfully terminated.");
        }
        public void LogoutCommand_Run_LetsNotificationHandleStatus()
        {
            var response = new Saml2LogoutResponse(Saml2StatusCode.Requester)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                SigningAlgorithm   = SecurityAlgorithms.RsaSha256Signature,
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET", bindResult.Location,
                                              "http://sp-internal.example.com/path/Saml2", null, null, null);

            var options = StubFactory.CreateOptions();

            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/path/");
            options.Notifications.ProcessSingleLogoutResponseStatus = (logoutResponse, requestState) => true;

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName).Run(request, options);

            actual.Location.Should().BeEquivalentTo(options.SPOptions.PublicOrigin);
        }
        public void Saml2LogoutResponse_FromXml_Nullcheck()
        {
            Action a = () => Saml2LogoutResponse.FromXml(null);

            a.ShouldThrow <ArgumentNullException>()
            .And.ParamName.Should().Be("xml");
        }
Example #11
0
        public async Task <IActionResult> SingleLogout()
        {
            var requestBinding = new Saml2PostBinding();
            var request        = new Saml2LogoutRequest(_configuration);
            Saml2StatusCodes status;

            try
            {
                requestBinding.Unbind(Request.ToGenericHttpRequest(), request);
                await request.DeleteSession(HttpContext);

                status = Saml2StatusCodes.Success;
            }
            catch (Exception)
            {
                status = Saml2StatusCodes.RequestDenied;
            }

            var responseBinding = new Saml2PostBinding();

            responseBinding.RelayState = requestBinding.RelayState;

            var response = new Saml2LogoutResponse(_configuration)
            {
                InResponseToAsString = request.IdAsString,
                Status = status
            };

            return(responseBinding.Bind(response)
                   .ToActionResult());
        }
Example #12
0
        private async Task CreateLogoutResponse(IOwinContext context)
        {
            var requestData = await context.ToHttpRequestData(Options.DataProtector.Unprotect);

            var binding = Saml2Binding.Get(requestData);

            if (binding == null)
            {
                context.Response.StatusCode = 400;
                return;
            }

            var unbindResult  = binding.Unbind(requestData, null);
            var logoutRequest = Saml2LogoutRequest.FromXml(unbindResult.Data);

            context.Authentication.SignOut();

            var logoutResponse = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri(new Uri(logoutRequest.Issuer.Id + "/"), "Logout"),
                SigningCertificate = Options.SigningCertificate,
                InResponseTo       = new Saml2Id(logoutRequest.Id.Value),
                Issuer             = new EntityId(GetAbsoluteUri(context.Request, MetadataPath).AbsoluteUri),
                RelayState         = unbindResult.RelayState
            };

            Saml2Binding.Get(Saml2BindingType.HttpRedirect)
            .Bind(logoutResponse)
            .Apply(context, Options.DataProtector);
        }
        public ActionResult SingleLogout()
        {
            Saml2StatusCodes status;
            var requestBinding = new Saml2RedirectBinding();
            var logoutRequest  = new Saml2LogoutRequest();

            try
            {
                requestBinding.Unbind(Request, logoutRequest, CertificateUtil.Load("~/App_Data/signing-adfs.test_Certificate.crt"));
                status = Saml2StatusCodes.Success;
            }
            catch (Exception exc)
            {
                // log exception
                Debug.WriteLine("SingleLogout error: " + exc.ToString());
                status = Saml2StatusCodes.RequestDenied;
            }

            var responsebinding = new Saml2RedirectBinding();

            responsebinding.RelayState = requestBinding.RelayState;
            var saml2LogoutResponse = new Saml2LogoutResponse
            {
                InResponseTo = logoutRequest.Id,
                Status       = status,
                Issuer       = new EndpointReference("http://udv.itfoxtec.com/webapptest"),
                Destination  = new EndpointAddress("https://udv.itfoxtec.com/adfs/ls/")
            };

            saml2LogoutResponse.DeleteSession();
            return(responsebinding.Bind(saml2LogoutResponse, CertificateUtil.Load("~/App_Data/webapptest_certificate.pfx")).ToActionResult());
        }
Example #14
0
        public void LogoutCommand_Run_RejectsUnsignedLogoutResponse()
        {
            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer         = new EntityId("https://idp.example.com"),
                InResponseTo   = new Saml2Id(),
                RelayState     = relayState
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET",
                                              bindResult.Location,
                                              "http://sp-internal.example.com/path/Saml2",
                                              null,
                                              new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null));

            var options = StubFactory.CreateOptions();

            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Invoking(c => c.Run(request, options))
            .Should().Throw <UnsuccessfulSamlOperationException>();
        }
Example #15
0
        public void LogoutCommand_Run_AcceptsUnsignedLogoutResponseIfCompatFlagSet()
        {
            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer         = new EntityId("https://idp.example.com"),
                InResponseTo   = new Saml2Id(),
                RelayState     = relayState
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET",
                                              bindResult.Location,
                                              "http://sp-internal.example.com/path/Saml2",
                                              null,
                                              new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null));

            var options = StubFactory.CreateOptions();

            options.SPOptions.Compatibility.AcceptUnsignedLogoutResponses = true;

            // Should not throw.
            CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
            .Run(request, options);
        }
Example #16
0
        public ActionResult SingleLogout()
        {
            Saml2StatusCodes status;
            var requestBinding = new Saml2PostBinding();
            var logoutRequest  = new Saml2LogoutRequest(config, ClaimsPrincipal.Current);

            try
            {
                requestBinding.Unbind(Request.ToGenericHttpRequest(), logoutRequest);
                status = Saml2StatusCodes.Success;
                logoutRequest.DeleteSession();
            }
            catch (Exception exc)
            {
                // log exception
                Debug.WriteLine("SingleLogout error: " + exc.ToString());
                status = Saml2StatusCodes.RequestDenied;
            }

            var responsebinding = new Saml2PostBinding();

            responsebinding.RelayState = requestBinding.RelayState;
            var saml2LogoutResponse = new Saml2LogoutResponse(config)
            {
                InResponseToAsString = logoutRequest.IdAsString,
                Status = status,
            };

            return(responsebinding.Bind(saml2LogoutResponse).ToActionResult());
        }
Example #17
0
        private async Task <IActionResult> LogoutResponseAsync <T>(Saml2Configuration samlConfig, string inResponseTo, string relayState, string singleLogoutResponseUrl, Saml2Binding <T> binding, Saml2StatusCodes status, string sessionIndex)
        {
            binding.RelayState = relayState;

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig)
            {
                InResponseTo = new Saml2Id(inResponseTo),
                Status       = status,
                Destination  = new Uri(singleLogoutResponseUrl),
                SessionIndex = sessionIndex
            };

            binding.Bind(saml2LogoutResponse);
            logger.ScopeTrace(() => $"SAML Single Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);
            logger.ScopeTrace(() => $"Single logged out response URL '{singleLogoutResponseUrl}'.");
            logger.ScopeTrace(() => "Down, SAML Single Logout response.", triggerEvent: true);

            await sequenceLogic.RemoveSequenceDataAsync <SamlDownSequenceData>();

            securityHeaderLogic.AddFormActionAllowAll();

            if (binding is Saml2Binding <Saml2RedirectBinding> )
            {
                return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync());
            }
            if (binding is Saml2Binding <Saml2PostBinding> )
            {
                return(await(binding as Saml2PostBinding).ToActionFormResultAsync());
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Example #18
0
        public void LogoutCommand_Run_HandlesLogoutResponse_UsesApplicationPathWhenStateDisabled()
        {
            var response = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                SigningAlgorithm   = SecurityAlgorithms.RsaSha256Signature,
                RelayState         = null
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var applicationPath = "http://sp-internal.example.com/path/Saml2/";
            var request         = new HttpRequestData("GET", bindResult.Location, applicationPath, null, null);

            var options = StubFactory.CreateOptions();

            options.SPOptions.Compatibility.DisableLogoutStateCookie = true;

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
                         .Run(request, options);

            var expected = new CommandResult
            {
                Location        = new Uri(applicationPath),
                HttpStatusCode  = HttpStatusCode.SeeOther,
                ClearCookieName = null
            };

            actual.Should().BeEquivalentTo(expected);
        }
        public ActionResult LoggedOut()
        {
            var response = new Saml2LogoutResponse();

            response.DeleteSession();

            return(RedirectToAction("Index"));
        }
Example #20
0
        public IActionResult LoggedOut()
        {
            var binding  = new Saml2PostBinding();
            var response = new Saml2LogoutResponse(_configuration);

            binding.Unbind(Request.ToGenericHttpRequest(), response);
            return(Redirect(Url.Action("Index", "Home")));
        }
Example #21
0
        public void LogoutCommand_Run_HandlesLogoutResponse()
        {
            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                SigningAlgorithm   = SecurityAlgorithms.RsaSha256Signature,
                RelayState         = relayState
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET",
                                              bindResult.Location,
                                              "http://sp-internal.example.com/path/Saml2",
                                              null,
                                              new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null));

            var options = StubFactory.CreateOptions();

            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/path/");

            CommandResult notifiedCommandResult = null;

            options.Notifications.LogoutCommandResultCreated = cr =>
            {
                notifiedCommandResult = cr;
            };
            var responseUnboundCalled = false;

            options.Notifications.MessageUnbound = ur =>
            {
                ur.Should().NotBeNull();
                responseUnboundCalled = true;
            };

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
                         .Run(request, options);

            actual.Should().BeSameAs(notifiedCommandResult);
            responseUnboundCalled.Should().BeTrue("the ResponseUnbound notification should have been called.");

            var expected = new CommandResult
            {
                Location            = new Uri("http://loggedout.example.com"),
                HttpStatusCode      = HttpStatusCode.SeeOther,
                ClearCookieName     = StoredRequestState.CookieNameBase + relayState,
                SetCookieSecureFlag = true
            };

            actual.Should().BeEquivalentTo(expected);
        }
Example #22
0
        private IActionResult SingleLogoutResponseInternal()
        {
            var responseBinding = new Saml2PostBinding();
            var relyingParty    = ValidateRelyingParty(ReadRelyingPartyFromLogoutResponse(responseBinding));

            var saml2LogoutResponse = new Saml2LogoutResponse(saml2Config);

            saml2LogoutResponse.SignatureValidationCertificates = new X509Certificate2[] { relyingParty.SignatureValidationCertificate };
            responseBinding.Unbind(Request.ToGenericHttpRequest(), saml2LogoutResponse);

            return(Redirect(Url.Content("~/")));
        }
        protected virtual async Task ApplyResponseLogoutAsync()
        {
            var options = Options as Saml2AuthenticationOptions;

            if (options == null)
            {
                return;
            }

            if (_configuration == null)
            {
                _configuration = await options.ConfigurationManager.GetConfigurationAsync(Context.Request.CallCancelled);
            }

            var request = Context.Get <HttpContextBase>(typeof(HttpContextBase).FullName).Request;

            foreach (var signingKey in _configuration.SigningKeys.OfType <X509SecurityKey>())
            {
                var binding = new Saml2PostBinding();
                Saml2LogoutResponse response = null;

                try
                {
                    response = binding.Unbind(request, new Saml2LogoutResponse(), signingKey.Certificate) as Saml2LogoutResponse;
                }
                catch (Saml2ResponseException)
                {
                }

                if (response == null || response.Status != Saml2StatusCodes.Success)
                {
                    continue;
                }

                var relayState = binding.GetRelayStateQuery();
                var properties = relayState.ContainsKey(_relayStateWctx)
                                        ? Options.StateDataFormat.Unprotect(relayState[_relayStateWctx])
                                        : new AuthenticationProperties();

                if (string.IsNullOrWhiteSpace(properties.RedirectUri))
                {
                    properties.RedirectUri = GetRedirectUri(binding, options);
                }

                ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("RedirectUri={0}", properties.RedirectUri));

                Response.Redirect(properties.RedirectUri);

                return;
            }
        }
Example #24
0
        private void ValidateLogoutResponse(SamlDownParty party, Saml2LogoutResponse saml2LogoutResponse)
        {
            var requestIssuer = saml2LogoutResponse.Issuer;

            logger.SetScopeProperty("Issuer", requestIssuer);

            if (!party.Issuer.Equals(requestIssuer))
            {
                throw new SamlRequestException($"Invalid issuer '{requestIssuer}'.")
                      {
                          RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                      };
            }
        }
Example #25
0
        public void LogoutCommand_Run_HandlesLogoutResponse_InPost()
        {
            var relayState = "TestState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/Saml2/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert
            };

            var xml = XmlHelpers.XmlDocumentFromString(response.ToXml());

            xml.Sign(SignedXmlHelper.TestCert);

            var responseData = Convert.ToBase64String(Encoding.UTF8.GetBytes(xml.OuterXml));

            var httpRequest = new HttpRequestData(
                "POST",
                new Uri("http://something"),
                "/path",
                new KeyValuePair <string, IEnumerable <string> >[]
            {
                new KeyValuePair <string, IEnumerable <string> >("SAMLResponse", new[] { responseData }),
                new KeyValuePair <string, IEnumerable <string> >("RelayState", new[] { relayState })
            },
                Enumerable.Empty <KeyValuePair <string, string> >(),
                null)
            {
                StoredRequestState = new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null)
            };

            var options = StubFactory.CreateOptions();

            options.SPOptions.ServiceCertificates.Add(SignedXmlHelper.TestCert);

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
                         .Run(httpRequest, options);

            var expected = new CommandResult
            {
                Location        = new Uri("http://loggedout.example.com"),
                HttpStatusCode  = HttpStatusCode.SeeOther,
                ClearCookieName = StoredRequestState.CookieNameBase + relayState,
            };

            actual.Should().BeEquivalentTo(expected);
        }
        public void Saml2LogoutResponse_ToXml()
        {
            var subject = new Saml2LogoutResponse(Saml2StatusCode.Requester)
            {
                Issuer         = new EntityId("https://ServiceProvider.com/SAML"),
                DestinationUrl = new Uri("https://IdentityProvider.com/Logout"),
                InResponseTo   = new Saml2Id()
            };

            var xmlDoc = XmlHelpers.CreateSafeXmlDocument();

            subject.AppendTo(xmlDoc);
            var expected = xmlDoc.OuterXml;

            subject.ToXml().Should().Be(expected);
        }
Example #27
0
        private IActionResult LogoutResponse(Saml2Id inResponseTo, Saml2StatusCodes status, string relayState, string sessionIndex, RelyingParty relyingParty)
        {
            var responsebinding = new Saml2PostBinding();

            responsebinding.RelayState = relayState;

            var saml2LogoutResponse = new Saml2LogoutResponse(saml2Config)
            {
                InResponseTo = inResponseTo,
                Status       = status,
                Destination  = relyingParty.SingleLogoutResponseDestination,
                SessionIndex = sessionIndex
            };

            return(responsebinding.Bind(saml2LogoutResponse).ToActionResult());
        }
        public void LogoutCommand_Run_HandlesLogoutResponse()
        {
            var relayState = "MyRelayState";
            var response   = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = new Uri("http://sp.example.com/path/AuthServices/logout"),
                Issuer             = new EntityId("https://idp.example.com"),
                InResponseTo       = new Saml2Id(),
                SigningCertificate = SignedXmlHelper.TestCert,
                RelayState         = relayState
            };

            var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                             .Bind(response);

            var request = new HttpRequestData("GET",
                                              bindResult.Location,
                                              "http://sp-internal.example.com/path/AuthServices",
                                              null,
                                              new StoredRequestState(null, new Uri("http://loggedout.example.com"), null, null));

            var options = StubFactory.CreateOptions();

            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/path/");

            CommandResult notifiedCommandResult = null;

            options.Notifications.LogoutCommandResultCreated = cr =>
            {
                notifiedCommandResult = cr;
            };

            var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName)
                         .Run(request, options);

            actual.Should().BeSameAs(notifiedCommandResult);

            var expected = new CommandResult
            {
                Location        = new Uri("http://loggedout.example.com"),
                HttpStatusCode  = HttpStatusCode.SeeOther,
                ClearCookieName = "Kentor." + relayState
            };

            actual.ShouldBeEquivalentTo(expected);
        }
Example #29
0
        private async Task <IActionResult> SingleLogoutResponseAsync <T>(SamlDownParty party, Saml2Binding <T> binding)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlDownConfig(party);

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig);

            binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
            logger.ScopeTrace($"SAML Single Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.");

            ValidateLogoutResponse(party, saml2LogoutResponse);
            await sequenceLogic.ValidateSequenceAsync(binding.RelayState);

            binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
            logger.ScopeTrace("Down, SAML Single Logout response accepted.", triggerEvent: true);

            return(await singleLogoutDownLogic.HandleSingleLogoutAsync());
        }
Example #30
0
        private static CommandResult HandleRequest(UnbindResult unbindResult, HttpRequestData httpRequest, IOptions options)
        {
            var request = Saml2LogoutRequest.FromXml(unbindResult.Data);

            var idp = options.IdentityProviders[request.Issuer];

            if (options.SPOptions.SigningServiceCertificate == null)
            {
                throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture,
                                                                     "Received a LogoutRequest from \"{0}\" but cannot reply because single logout responses " +
                                                                     "must be signed and there is no signing certificate configured. Looks like the idp is " +
                                                                     "configured for Single Logout despite Saml2 not exposing that functionality in the metadata.",
                                                                     request.Issuer.Id));
            }

            if (idp.SingleLogoutServiceResponseUrl == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                  "Received a LogoutRequest from \"{0}\" but cannot reply because on logout endpoint is " +
                                                                  "configured on the idp. Set a SingleLogoutServiceUrl if the idp is configured manually, " +
                                                                  "or check that the idp metadata contains a SingleLogoutService endpoint.",
                                                                  idp.EntityId.Id));
            }

            var response = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = idp.SingleLogoutServiceResponseUrl,
                SigningCertificate = options.SPOptions.SigningServiceCertificate,
                SigningAlgorithm   = idp.OutboundSigningAlgorithm,
                InResponseTo       = request.Id,
                Issuer             = options.SPOptions.EntityId,
                RelayState         = unbindResult.RelayState
            };

            options.Notifications.LogoutResponseCreated(response, request, httpRequest.User, idp);

            options.SPOptions.Logger.WriteInformation("Got a logout request " + request.Id
                                                      + ", responding with logout response " + response.Id);

            var result = Saml2Binding.Get(idp.SingleLogoutServiceBinding).Bind(
                response, options.SPOptions.Logger, options.Notifications.LogoutResponseXmlCreated);

            result.TerminateLocalSession = true;
            return(result);
        }