public void CommandResultExtensions_Apply() { var context = TestHelpers.CreateHttpContext(); var state = new StoredRequestState( new EntityId("https://idp.example.com"), new Uri("https://sp.example.com/ReturnUrl"), new Saml2Id(), new Dictionary <string, string>() { { "Key1", "Value1" }, { "Key2", "value2" } }); var commandResult = new CommandResult() { HttpStatusCode = System.Net.HttpStatusCode.Redirect, Location = new Uri("https://destination.com"), SetCookieName = "Saml2.123", RelayState = "123", RequestState = state, ContentType = "application/json", Content = "{ value: 42 }", ClearCookieName = "Clear-Cookie", }; commandResult.Apply(context, new StubDataProtector()); var expectedCookieData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(commandResult.GetSerializedRequestState())); context.Response.StatusCode.Should().Be(302); context.Response.Headers["Location"].SingleOrDefault() .Should().Be("https://destination.com/", "location header should be set"); context.Response.Cookies.Received().Append( "Saml2.123", expectedCookieData, Arg.Is <CookieOptions>(co => co.HttpOnly)); context.Response.Cookies.Received().Append( "Clear-Cookie", null, Arg.Is <CookieOptions>(co => co.Expires.Value.UtcTicks == 0)); context.Response.ContentType .Should().Be("application/json", "content type should be set"); context.Response.Body.Seek(0, SeekOrigin.Begin); new StreamReader(context.Response.Body).ReadToEnd() .Should().Be("{ value: 42 }", "content should be set"); }
public void HttpContextExtensions_ToHttpRequestData_ReadsRelayStateCookie() { var context = TestHelpers.CreateHttpContext(); context.Request.QueryString = new QueryString("?RelayState=SomeState"); var storedRequestState = new StoredRequestState( null, new Uri("http://sp.example.com"), null, null); var cookieData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(storedRequestState.Serialize())); context.Request.Cookies = new StubCookieCollection( Enumerable.Repeat(new KeyValuePair <string, string>( StoredRequestState.CookieNameBase + "SomeState", cookieData), 1)); var actual = context.ToHttpRequestData(StubDataProtector.Unprotect); actual.StoredRequestState.Should().BeEquivalentTo(storedRequestState); }
public void HttpContextExtensions_ToHttpRequestData_ReadsRelayStateCookie() { var context = TestHelpers.CreateHttpContext(); context.Request.QueryString = new QueryString("?RelayState=SomeState"); var storedRequestState = new StoredRequestState( null, new Uri("http://sp.example.com"), null, null); var cookieData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(storedRequestState.Serialize())); var cookieName = $"{StoredRequestState.CookieNameBase}SomeState"; var cookieManager = Substitute.For <ICookieManager>(); cookieManager.GetRequestCookie(context, cookieName).Returns(cookieData); var actual = context.ToHttpRequestData(cookieManager, StubDataProtector.Unprotect); actual.StoredRequestState.Should().BeEquivalentTo(storedRequestState); }
public async Task CommandResultExtensions_Apply() { var context = TestHelpers.CreateHttpContext(); var state = new StoredRequestState( new EntityId("https://idp.example.com"), new Uri("https://sp.example.com/ReturnUrl"), new Saml2Id(), new Dictionary <string, string>() { { "Key1", "Value1" }, { "Key2", "value2" } }); var redirectLocation = "https://destination.com"; var commandResult = new CommandResult() { HttpStatusCode = System.Net.HttpStatusCode.Redirect, Location = new Uri(redirectLocation), SetCookieName = "Saml2.123", RelayState = "123", RequestState = state, ContentType = "application/json", Content = "{ value: 42 }", ClearCookieName = "Clear-Cookie", Principal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "SomerUser") }, "authType")), RelayData = new Dictionary <string, string>() { { "Relayed", "Value" } } }; ClaimsPrincipal principal = null; AuthenticationProperties authProps = null; var authService = Substitute.For <IAuthenticationService>(); context.RequestServices.GetService(typeof(IAuthenticationService)) .Returns(authService); await authService.SignInAsync( context, "TestSignInScheme", Arg.Do <ClaimsPrincipal>(p => principal = p), Arg.Do <AuthenticationProperties>(ap => authProps = ap)); commandResult.Apply(context, new StubDataProtector(), "TestSignInScheme"); var expectedCookieData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(commandResult.GetSerializedRequestState())); context.Response.StatusCode.Should().Be(302); context.Response.Headers["Location"].SingleOrDefault() .Should().Be("https://destination.com/", "location header should be set"); context.Response.Cookies.Received().Append( "Saml2.123", expectedCookieData, Arg.Is <CookieOptions>(co => co.HttpOnly && co.SameSite == SameSiteMode.None)); context.Response.Cookies.Received().Delete("Clear-Cookie"); context.Response.ContentType .Should().Be("application/json", "content type should be set"); context.Response.Body.Seek(0, SeekOrigin.Begin); new StreamReader(context.Response.Body).ReadToEnd() .Should().Be("{ value: 42 }", "content should be set"); principal.HasClaim(ClaimTypes.NameIdentifier, "SomerUser").Should().BeTrue(); authProps.Items["Relayed"].Should().Be("Value"); authProps.RedirectUri.Should().Be(redirectLocation); }
public async Task Saml2Handler_Acs_Works() { var context = new Saml2HandlerTestContext(); context.HttpContext.Request.Method = "POST"; context.HttpContext.Request.Path = "/Saml2/Acs"; var authProps = new AuthenticationProperties() { IssuedUtc = new DateTimeOffset(DateTime.UtcNow) }; authProps.Items["Test"] = "TestValue"; var state = new StoredRequestState( new EntityId("https://idp.example.com"), new Uri("https://localhost/LoggedIn"), new Saml2Id("InResponseToId"), authProps.Items); var relayState = SecureKeyGenerator.CreateRelayState(); var cookieData = HttpRequestData.ConvertBinaryData( StubDataProtector.Protect(state.Serialize())); var cookieName = $"Kentor.{relayState}"; context.HttpContext.Request.Cookies = new StubCookieCollection( Enumerable.Repeat(new KeyValuePair <string, string>( cookieName, cookieData), 1)); 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 + @""" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"" InResponseTo=""InResponseToId"" > <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 + @"_Assertion1"" 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:AudienceRestriction> <saml2:Audience>http://sp.example.com/saml2</saml2:Audience> </saml2:AudienceRestriction> </saml2:Conditions> </saml2:Assertion> </saml2p:Response>"; var form = Substitute.For <IFormCollection>(); IEnumerator <KeyValuePair <string, StringValues> > formCollectionEnumerator = new KeyValuePair <string, StringValues>[] { new KeyValuePair <string, StringValues>( "SAMLResponse", new StringValues( Convert.ToBase64String( Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response))))), new KeyValuePair <string, StringValues>( "RelayState", new StringValues(relayState)) }.AsEnumerable().GetEnumerator(); form.GetEnumerator().Returns(formCollectionEnumerator); context.HttpContext.Request.Form.Returns(form); var authService = Substitute.For <IAuthenticationService>(); context.HttpContext.RequestServices.GetService(typeof(IAuthenticationService)) .Returns(authService); ClaimsPrincipal principal = null; AuthenticationProperties actualAuthProps = null; await authService.SignInAsync( context.HttpContext, TestHelpers.defaultSignInScheme, Arg.Do <ClaimsPrincipal>(p => principal = p), Arg.Do <AuthenticationProperties>(ap => actualAuthProps = ap)); await context.Subject.HandleRequestAsync(); principal.HasClaim(ClaimTypes.NameIdentifier, "SomeUser").Should().BeTrue(); actualAuthProps.IssuedUtc.Should().Be(authProps.IssuedUtc); actualAuthProps.Items["Test"].Should().Be("TestValue"); context.HttpContext.Response.Headers["Location"].Single().Should().Be( state.ReturnUrl.OriginalString); context.HttpContext.Response.StatusCode.Should().Be(303); }