public override CommandResult Bind(string payload, Uri destinationUrl, string messageName) { if (payload == null) { throw new ArgumentNullException(nameof(payload)); } if (destinationUrl == null) { throw new ArgumentNullException(nameof(destinationUrl)); } if (messageName == null) { throw new ArgumentNullException(nameof(messageName)); } var encodedXml = Convert.ToBase64String( Encoding.UTF8.GetBytes(payload)); var cr = new CommandResult() { ContentType = "text/html", Content = String.Format( CultureInfo.InvariantCulture, PostHtmlFormatString, destinationUrl, messageName, encodedXml) }; return cr; }
public void CommandResultExtensions_Apply_Cookie() { var cr = new CommandResult() { RequestState = new StoredRequestState( new EntityId("http://idp.example.com"), new Uri("http://sp.example.com/loggedout"), new Saml2Id("id123"), null), SetCookieName = "CookieName" }; var context = OwinTestHelpers.CreateOwinContext(); var dataProtector = new StubDataProtector(); cr.Apply(context, dataProtector); var setCookieHeader = context.Response.Headers["Set-Cookie"]; var protectedData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(cr.GetSerializedRequestState())); var expected = $"CookieName={protectedData}; path=/; HttpOnly"; setCookieHeader.Should().Be(expected); }
public void Saml2RedirectBinding_Bind() { // Example from http://en.wikipedia.org/wiki/SAML_2.0#HTTP_Redirect_Binding var xmlData = @"<?xml version=""1.0"" encoding=""UTF-8""?> <samlp:AuthnRequest xmlns:samlp=""urn:oasis:names:tc:SAML:2.0:protocol"" xmlns:saml=""urn:oasis:names:tc:SAML:2.0:assertion"" ID=""aaf23196-1773-2113-474a-fe114412ab72"" Version=""2.0"" IssueInstant=""2004-12-05T09:21:59Z"" AssertionConsumerServiceIndex=""0"" AttributeConsumingServiceIndex=""0""> <saml:Issuer>https://sp.example.com/SAML2</saml:Issuer> <samlp:NameIDPolicy AllowCreate=""true"" Format=""urn:oasis:names:tc:SAML:2.0:nameid-format:transient""/> </samlp:AuthnRequest> "; var serializedData = "fZFfa8IwFMXfBb9DyXvaJtZ1BqsURRC2Mabbw95ivc5Am3TJrXPffmmLY3%2FA15Pzuyf33On8XJXBCaxTRmeEhTEJQBdmr%2FRbRp63K3pL5rPhYOpkVdYib%2FCon%2BC9AYfDQRB4WDvRvWWksVoY6ZQTWlbgBBZik9%2FfCR7GorYGTWFK8pu6DknnwKL%2FWEetlxmR8sBHbHJDWZqOKGdsRJM0kfQAjCUJ43KX8s78ctnIz%2Blp5xpYa4dSo1fjOKGM03i8jSeCMzGevHa2%2FBK5MNo1FdgN2JMqPLmHc0b6WTmiVbsGoTf5qv66Zq2t60x0wXZ2RKydiCJXh3CWVV1CWJgqanfl0%2Bin8xutxYOvZL18NKUqPlvZR5el%2BVhYkAgZQdsA6fWVsZXE63W2itrTQ2cVaKV2CjSSqL1v9P%2FAXv4C"; var destinationUrl = new Uri("http://www.example.com/acs"); var subject = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(xmlData, destinationUrl, null); var expected = new CommandResult() { Location = new Uri("http://www.example.com/acs?SAMLRequest=" + serializedData), HttpStatusCode = System.Net.HttpStatusCode.SeeOther, }; subject.ShouldBeEquivalentTo(expected); }
public void CommandResultExtensions_ToActionResult_UknownStatusCode() { var cr = new CommandResult() { HttpStatusCode = System.Net.HttpStatusCode.SwitchingProtocols }; Action a = () => cr.ToActionResult(); a.ShouldThrow<NotImplementedException>(); }
public void CommandResultExtensions_ToActionResult_SeeOther() { var strLocation = "http://example.com/location?X=A%20B%3DZ"; var cr = new CommandResult() { HttpStatusCode = System.Net.HttpStatusCode.SeeOther, Location = new Uri(strLocation) }; var subject = cr.ToActionResult(); subject.Should().BeOfType<RedirectResult>().And .Subject.As<RedirectResult>().Url.Should().Be(strLocation); }
public void CommandResultExtensions_ToActionResult_Ok() { var cr = new CommandResult() { Content = "Some Content!", ContentType = "application/whatever+text" }; var subject = cr.ToActionResult(); subject.Should().BeOfType<ContentResult>().And .Subject.As<ContentResult>().Content.Should().Be(cr.Content); subject.As<ContentResult>().ContentType.Should().Contain(cr.ContentType); }
public void CommandResultExtensions_Apply_Redirect() { string redirectUrl = "http://somewhere.else.example.com?Foo=Bar%20XYZ"; var cr = new CommandResult() { HttpStatusCode = HttpStatusCode.SeeOther, Location = new Uri(redirectUrl) }; var context = OwinTestHelpers.CreateOwinContext(); cr.Apply(context); context.Response.StatusCode.Should().Be(303); context.Response.Headers["Location"].Should().Be(redirectUrl); }
public void CommandResultExtensions_Apply_ClearCookie() { var cr = new CommandResult() { ClearCookieName = "CookieName" }; var context = OwinTestHelpers.CreateOwinContext(); var dataProtector = new StubDataProtector(); cr.Apply(context, dataProtector); var setCookieHeader = context.Response.Headers["Set-Cookie"]; var expected = "CookieName=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"; setCookieHeader.Should().Be(expected); }
public void Saml2RedirectBinding_Bind() { var message = new Saml2MessageImplementation { XmlData = ExampleXmlData, DestinationUrl = new Uri("http://www.example.com/sso"), MessageName = "SAMLRequest" }; var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message); var expected = new CommandResult() { Location = new Uri("http://www.example.com/sso?SAMLRequest=" + ExampleSerializedData), HttpStatusCode = System.Net.HttpStatusCode.SeeOther, }; result.ShouldBeEquivalentTo(expected); }
public void Saml2PostBinding_Bind() { var message = new Saml2MessageImplementation { XmlData = "<root><content>data</content></root>", DestinationUrl = new Uri("http://www.example.com/acs"), MessageName = "SAMLMessageName" }; var result = Saml2Binding.Get(Saml2BindingType.HttpPost).Bind(message); var expected = new CommandResult() { ContentType = "text/html", Content = @"<?xml version=""1.0"" encoding=""UTF-8""?> <!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN"" ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd""> <html xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en""> <body onload=""document.forms[0].submit()""> <noscript> <p> <strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed. </p> </noscript> <form action=""http://www.example.com/acs"" method=""post""> <div> <input type=""hidden"" name=""SAMLMessageName"" value=""PHJvb3Q+PGNvbnRlbnQ+ZGF0YTwvY29udGVudD48L3Jvb3Q+""/> </div> <noscript> <div> <input type=""submit"" value=""Continue""/> </div> </noscript> </form> </body> </html>" }; result.ShouldBeEquivalentTo(expected); }
private static void ApplyCookies(CommandResult commandResult, IOwinContext context, IDataProtector dataProtector) { var serializedCookieData = commandResult.GetSerializedRequestState(); if (serializedCookieData != null) { var protectedData = HttpRequestData.ConvertBinaryData( dataProtector.Protect(serializedCookieData)); context.Response.Cookies.Append( commandResult.SetCookieName, protectedData, new CookieOptions() { HttpOnly = true, }); } commandResult.ApplyClearCookie(context); }
public void CommandResultExtensions_Apply_Cookie() { var cr = new CommandResult() { SetCookieData = "???>>>SomeData", SetCookieName = "CookieName" }; var context = OwinTestHelpers.CreateOwinContext(); var dataProtector = new StubDataProtector(); cr.Apply(context, dataProtector); var setCookieHeader = context.Response.Headers["Set-Cookie"]; var protectedData = StubDataProtector.Protect(cr.SetCookieData); var expected = $"CookieName={protectedData}; path=/; HttpOnly"; setCookieHeader.Should().Be(expected); }
public override CommandResult Bind(ISaml2Message message) { if(message == null) { throw new ArgumentNullException(nameof(message)); } var xml = message.ToXml(); if(message.SigningCertificate != null) { var xmlDoc = new XmlDocument() { PreserveWhitespace = true }; xmlDoc.LoadXml(xml); xmlDoc.Sign(message.SigningCertificate, true); xml = xmlDoc.OuterXml; } var encodedXml = Convert.ToBase64String(Encoding.UTF8.GetBytes(xml)); var relayStateHtml = string.IsNullOrEmpty(message.RelayState) ? null : string.Format(CultureInfo.InvariantCulture, PostHtmlRelayStateFormatString, message.RelayState); var cr = new CommandResult() { ContentType = "text/html", Content = String.Format( CultureInfo.InvariantCulture, PostHtmlFormatString, message.DestinationUrl, relayStateHtml, message.MessageName, encodedXml) }; return cr; }
public void CommandResultExtensions_Apply_Content() { var cr = new CommandResult() { Content = "Some Content!", ContentType = "application/whatever+text" }; var context = OwinTestHelpers.CreateOwinContext(); cr.Apply(context, null); context.Response.StatusCode.Should().Be(200); context.Response.ContentType.Should().Be("application/whatever+text"); context.Response.Body.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(context.Response.Body)) { var bodyText = reader.ReadToEnd(); bodyText.Should().Be("Some Content!"); } }
public CommandResult Run(HttpRequestData request, IOptions options) { if(options == null) { throw new ArgumentNullException(nameof(options)); } var urls = new AuthServicesUrls(request, options); var metadata = options.SPOptions.CreateMetadata(urls); options.Notifications.MetadataCreated(metadata, urls); var result = new CommandResult() { Content = metadata.ToXmlString(options.SPOptions.SigningServiceCertificate), ContentType = "application/samlmetadata+xml" }; options.Notifications.MetadataCommandResultCreated(result); return result; }
public void SignInCommand_Run_ReturnsAuthnRequestForDefaultIdp() { var defaultDestination = Options.FromConfiguration.IdentityProviders.Default.SingleSignOnServiceUrl; var subject = new SignInCommand().Run( new HttpRequestData("GET", new Uri("http://example.com")), Options.FromConfiguration); var expected = new CommandResult() { HttpStatusCode = HttpStatusCode.SeeOther, Cacheability = (Cacheability) HttpCacheability.NoCache, Location = new Uri(defaultDestination + "?SAMLRequest=XYZ") }; subject.ShouldBeEquivalentTo(expected, options => options.Excluding(cr => cr.Location)); subject.Location.Host.Should().Be(defaultDestination.Host); var queries = HttpUtility.ParseQueryString(subject.Location.Query); queries.Should().HaveCount(1); queries.Keys[0].Should().Be("SAMLRequest"); queries[0].Should().NotBeEmpty(); }
private static CommandResult InitiateLogout(HttpRequestData request, Uri returnUrl, IOptions options) { string idpEntityId = null; Claim sessionIndexClaim = null; if (request.User != null) { idpEntityId = request.User.FindFirst(AuthServicesClaimTypes.LogoutNameIdentifier)?.Issuer; sessionIndexClaim = request.User.FindFirst(AuthServicesClaimTypes.SessionIndex); } CommandResult commandResult; IdentityProvider idp; if(idpEntityId != null && options.IdentityProviders.TryGetValue(new EntityId(idpEntityId), out idp) && sessionIndexClaim != null && idp.SingleLogoutServiceUrl != null && options.SPOptions.SigningServiceCertificate != null && !idp.DisableOutboundLogoutRequests) { var logoutRequest = idp.CreateLogoutRequest(request.User); commandResult = Saml2Binding.Get(idp.SingleLogoutServiceBinding) .Bind(logoutRequest); commandResult.RelayState = logoutRequest.RelayState; commandResult.RequestState = new StoredRequestState( idp.EntityId, returnUrl, logoutRequest.Id, null); if (!options.SPOptions.Compatibility.DisableLogoutStateCookie) { commandResult.SetCookieName = "Kentor." + logoutRequest.RelayState; } } else { commandResult = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther, Location = returnUrl }; } commandResult.TerminateLocalSession = true; return commandResult; }
private static CommandResult HandleResponse(UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl) { var status = Saml2LogoutResponse.FromXml(unbindResult.Data).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 = "Kentor." + unbindResult.RelayState; } commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl; return commandResult; }
public void Saml2PostBinding_Bind_SignsXml() { var message = new Saml2MessageImplementation { DestinationUrl = new Uri("http://www.example.com/acs"), XmlData = "<root ID=\"id\"><content>data</content></root>", MessageName = "SAMLMessageName", RelayState = "ABC1234", SigningCertificate = SignedXmlHelper.TestCert }; var signedXml = SignedXmlHelper.SignXml(message.XmlData, true); var expectedValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(signedXml)); var result = Saml2Binding.Get(Saml2BindingType.HttpPost).Bind(message); var expected = new CommandResult() { ContentType = "text/html", Content = @"<?xml version=""1.0"" encoding=""UTF-8""?> <!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN"" ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd""> <html xmlns=""http://www.w3.org/1999/xhtml"" xml:lang=""en""> <body onload=""document.forms[0].submit()""> <noscript> <p> <strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed. </p> </noscript> <form action=""http://www.example.com/acs"" method=""post""> <div> <input type=""hidden"" name=""RelayState"" value=""ABC1234""/> <input type=""hidden"" name=""SAMLMessageName"" value=""" + expectedValue + @"""/> </div> <noscript> <div> <input type=""submit"" value=""Continue""/> </div> </noscript> </form> </body> </html>" }; result.ShouldBeEquivalentTo(expected); }
public void LogoutCommand_Run_ReturnsLogoutRequest() { var user = new ClaimsPrincipal( new ClaimsIdentity(new Claim[] { new Claim(AuthServicesClaimTypes.LogoutNameIdentifier, ",,,,NameId", null, "https://idp.example.com"), new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com") }, "Federation")); var request = new HttpRequestData("GET", new Uri("http://sp-internal.example.com/AuthServices/Logout")); request.User = user; var options = StubFactory.CreateOptions(); options.SPOptions.ServiceCertificates.Add(SignedXmlHelper.TestCert); options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/"); 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 { HttpStatusCode = HttpStatusCode.SeeOther, TerminateLocalSession = true, // Deliberately not comparing Location. // Deliberately not comparing SetCookieName. RequestState = new StoredRequestState( new EntityId("https://idp.example.com"), new Uri("https://sp.example.com/"), null, null) }; actual.ShouldBeEquivalentTo(expected, opt => opt .Excluding(cr => cr.Location) .Excluding(cr => cr.SetCookieName) .Excluding(cr => cr.RequestState.MessageId)); var relayState = HttpUtility.ParseQueryString(actual.Location.Query)["RelayState"]; actual.SetCookieName.Should().Be("Kentor." + relayState); actual.Location.GetLeftPart(UriPartial.Path).Should().Be("https://idp.example.com/logout"); }
public void Saml2ArtifactBinding_Bind() { var message = new Saml2MessageImplementation { DestinationUrl = new Uri("http://example.com/destination"), MessageName = "ShouldBeIgnored", RelayState = "ABC& needs escape", XmlData = "<XML />", Issuer = new EntityId("http://idp.example.com"), }; var result = Saml2Binding.Get(Saml2BindingType.Artifact).Bind(message); var expected = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther }; result.ShouldBeEquivalentTo(expected, opt => opt.Excluding(r => r.Location)); result.Location.Query.Count(c => c == '=').Should().Be(2, "there are 2 params and = inside values should have been escaped"); var query = HttpUtility.ParseQueryString(result.Location.Query); Uri.UnescapeDataString(query["RelayState"]).Should().Be(message.RelayState); var artifact = Convert.FromBase64String( Uri.UnescapeDataString(query["SAMLart"])); ISaml2Message storedMessage; Saml2ArtifactBinding.PendingMessages.TryRemove(artifact, out storedMessage) .Should().BeTrue(); storedMessage.Should().BeSameAs(message); }
public void Saml2RedirectBinding_Bind_With_RelayState() { var message = new Saml2MessageImplementation { XmlData = "Data", RelayState = "SomeState that needs escaping #%=3", DestinationUrl = new Uri("http://host"), MessageName = "SAMLRequest" }; var expected = new CommandResult() { Location = new Uri("http://host?SAMLRequest=c0ksSQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%3D%3D" + "&RelayState=" + Uri.EscapeDataString(message.RelayState)), HttpStatusCode = System.Net.HttpStatusCode.SeeOther }; var result = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(message); result.ShouldBeEquivalentTo(expected); }
public void AcsCommand_Run_WithReturnUrl_SuccessfulResult() { var idp = Options.FromConfiguration.IdentityProviders.Default; var request = idp.CreateAuthenticateRequest( new Uri("http://localhost/testUrl.aspx"), StubFactory.CreateAuthServicesUrls()); var response = @"<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol"" xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion"" ID = """ + MethodBase.GetCurrentMethod().Name + @""" InResponseTo = """ + request.Id + @""" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z""> <saml2:Issuer> https://idp.example.com </saml2:Issuer> <saml2p:Status> <saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" /> </saml2p:Status> <saml2:Assertion Version=""2.0"" ID=""" + MethodBase.GetCurrentMethod().Name + @"_Assertion2"" IssueInstant=""2013-09-25T00:00:00Z""> <saml2:Issuer>https://idp.example.com</saml2:Issuer> <saml2:Subject> <saml2:NameID>SomeUser</saml2:NameID> <saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"" /> </saml2:Subject> <saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" /> </saml2:Assertion> </saml2p:Response>"; var formValue = Convert.ToBase64String(Encoding.UTF8.GetBytes( SignedXmlHelper.SignXml(response))); var r = new HttpRequestData( "POST", new Uri("http://localhost"), "/ModulePath", new KeyValuePair<string, string[]>[] { new KeyValuePair<string, string[]>("SAMLResponse", new string[] { formValue }) }); var ids = new ClaimsIdentity[] { new ClaimsIdentity("Federation"), new ClaimsIdentity("ClaimsAuthenticationManager") }; ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com")); ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", null, "ClaimsAuthenticationManagerStub")); var expected = new CommandResult() { Principal = new ClaimsPrincipal(ids), HttpStatusCode = HttpStatusCode.SeeOther, Location = new Uri("http://localhost/testUrl.aspx") }; new AcsCommand().Run(r, StubFactory.CreateOptions()) .ShouldBeEquivalentTo(expected, opt => opt.IgnoringCyclicReferences()); }
public void LogoutCommand_Run_HandlesLogoutResponse_InPost() { var relayState = "TestState"; 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 }; var xml = XmlHelpers.FromString(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, string[]>[] { new KeyValuePair<string, string[]>("SAMLResponse", new[] { responseData }), new KeyValuePair<string, string[]>("RelayState", new[] { relayState }) }, Enumerable.Empty<KeyValuePair<string, string>>(), null); httpRequest.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 = "Kentor." + relayState }; actual.ShouldBeEquivalentTo(expected); }
private static CommandResult InitiateLogout(HttpRequestData request, string returnPath, IOptions options) { var idpEntityId = ClaimsPrincipal.Current.FindFirst(AuthServicesClaimTypes.LogoutNameIdentifier)?.Issuer ?? ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier)?.Issuer; CommandResult commandResult; IdentityProvider idp; if(idpEntityId != null && options.IdentityProviders.TryGetValue(new EntityId(idpEntityId), out idp) && ClaimsPrincipal.Current.FindFirst(AuthServicesClaimTypes.SessionIndex) != null && idp.SingleLogoutServiceUrl != null && options.SPOptions.SigningServiceCertificate != null) { var logoutRequest = idp.CreateLogoutRequest(); commandResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect) .Bind(logoutRequest); commandResult.RequestState = new StoredRequestState( idp.EntityId, GetReturnUrl(request, returnPath, options), logoutRequest.Id, null); commandResult.SetCookieName = "Kentor." + logoutRequest.RelayState; } else { commandResult = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther, Location = GetReturnUrl(request, returnPath, options) }; } commandResult.TerminateLocalSession = true; return commandResult; }
private void LogoutCommand_Run_LocalLogout(IOptions options, ClaimsPrincipal user) { var subject = CommandFactory.GetCommand(CommandFactory.LogoutCommandName); var actual = subject.Run( new HttpRequestData("GET", new Uri("http://localhost/Logout?ReturnUrl=LoggedOut")) { User = user }, options); var expected = new CommandResult() { HttpStatusCode = HttpStatusCode.SeeOther, Location = new Uri("http://localhost/LoggedOut"), TerminateLocalSession = true }; actual.ShouldBeEquivalentTo(expected); }
public void LogoutCommand_Run_HandlesLogoutRequest_ReceivedThroughRedirectBinding() { var request = new Saml2LogoutRequest() { DestinationUrl = new Uri("http://sp.example.com/path/AuthServices/logout"), Issuer = new EntityId("https://idp.example.com"), SigningCertificate = SignedXmlHelper.TestCert, NameId = new Saml2NameIdentifier("NameId"), SessionIndex = "SessionID", }; var bindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect) .Bind(request); var httpRequest = new HttpRequestData("GET", bindResult.Location); var options = StubFactory.CreateOptions(); options.SPOptions.ServiceCertificates.Add(SignedXmlHelper.TestCert); CommandResult notifiedCommandResult = null; options.Notifications.LogoutCommandResultCreated = cr => { notifiedCommandResult = cr; }; // We're using unbind to verify the created message and UnBind // expects the issuer to be a known Idp for signature validation. // Add a dummy with the right issuer name and key. var dummyIdp = new IdentityProvider(options.SPOptions.EntityId, options.SPOptions); dummyIdp.SigningKeys.AddConfiguredKey(SignedXmlHelper.TestCert); options.IdentityProviders.Add(dummyIdp); var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName) .Run(httpRequest, options); var expected = new CommandResult() { HttpStatusCode = HttpStatusCode.SeeOther, TerminateLocalSession = true // Deliberately not comparing Location }; HttpUtility.ParseQueryString(actual.Location.Query)["Signature"] .Should().NotBeNull("LogoutResponse should be signed"); actual.ShouldBeEquivalentTo(expected, opt => opt.Excluding(cr => cr.Location)); actual.Should().BeSameAs(notifiedCommandResult); var actualUnbindResult = Saml2Binding.Get(Saml2BindingType.HttpRedirect) .Unbind(new HttpRequestData("GET", actual.Location), options); var actualMessage = actualUnbindResult.Data; var expectedMessage = XmlHelpers.FromString( $@"<samlp:LogoutResponse xmlns:samlp=""urn:oasis:names:tc:SAML:2.0:protocol"" xmlns=""urn:oasis:names:tc:SAML:2.0:assertion"" Destination=""https://idp.example.com/logout"" Version=""2.0""> <Issuer>{options.SPOptions.EntityId.Id}</Issuer> <samlp:Status> <samlp:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success""/> </samlp:Status> </samlp:LogoutResponse>").DocumentElement; // Set generated attributes to actual values. expectedMessage.SetAttribute("ID", actualMessage.GetAttribute("ID")); expectedMessage.SetAttribute("IssueInstant", actualMessage.GetAttribute("IssueInstant")); expectedMessage.SetAttribute("InResponseTo", request.Id.Value); actualMessage.Should().BeEquivalentTo(expectedMessage); actualUnbindResult.RelayState.Should().Be(request.RelayState); actualUnbindResult.TrustLevel.Should().Be(TrustLevel.Signature); }
public void LogoutCommand_Run_ReturnsLogoutRequest_IgnoresThreadPrincipal() { Thread.CurrentPrincipal = new ClaimsPrincipal( new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, "PrincipalWithNoSession"), }, "Federation")); var user = new ClaimsPrincipal( new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.NameIdentifier, "ApplicationNameId"), new Claim(AuthServicesClaimTypes.LogoutNameIdentifier, ",,,,Saml2NameId", null, "https://idp.example.com"), new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com") }, "Federation")); var request = new HttpRequestData("GET", new Uri("http://sp.example.com/AuthServices/Logout")); request.User = user; var options = StubFactory.CreateOptions(); options.SPOptions.ServiceCertificates.Add(SignedXmlHelper.TestCert); var actual = CommandFactory.GetCommand(CommandFactory.LogoutCommandName) .Run(request, options); var expected = new CommandResult { HttpStatusCode = HttpStatusCode.SeeOther, TerminateLocalSession = true, // Deliberately not comparing Location. RequestState = new StoredRequestState( new EntityId("https://idp.example.com"), new Uri("http://sp.example.com/"), null, null) }; actual.ShouldBeEquivalentTo(expected, opt => opt .Excluding(cr => cr.Location) .Excluding(cr => cr.SetCookieName) .Excluding(cr => cr.RequestState.MessageId)); actual.Location.GetLeftPart(UriPartial.Path).Should().Be("https://idp.example.com/logout"); }
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); }
public void CommandResultHttp_Apply_Content() { var response = Substitute.For<HttpResponseBase>(); var commandResult = new CommandResult { Content = "Some Content!", ContentType = "text" }; commandResult.Apply(response); response.Received().ContentType = "text"; response.Received().Write("Some Content!"); }