public async Task KentorAuthServicesAuthenticationMiddleware_RedirectsOnAuthChallenge()
        {
            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, null)), CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/idp");
        }
예제 #2
0
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectOnChallengeForAuthTypeInOptions()
        {
            var authenticationType = "someAuthName";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                                           new string[] { authenticationType }, null)),
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true)
            {
                AuthenticationType = authenticationType
            });

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/idp");
        }
예제 #3
0
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectoToSecondIdp_AuthenticationProperties()
        {
            var secondIdp         = Options.FromConfiguration.IdentityProviders[1];
            var secondDestination = secondIdp.SingleSignOnServiceUrl;
            var secondEntityId    = secondIdp.EntityId;

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                                           new string[] { "KentorAuthServices" }, new AuthenticationProperties(
                                               new Dictionary <string, string>()
            {
                { "idp", secondEntityId.Id }
            }))),
                CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();
            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith(secondDestination.ToString());
        }
예제 #4
0
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUrl = "http://sp.example.com/returnurl";

            var options = new KentorAuthServicesAuthenticationOptions(true);
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                                           new string[] { "KentorAuthServices" }, new AuthenticationProperties()
            {
                RedirectUri = returnUrl
            })),
                CreateAppBuilder(), options);

            var context = OwinTestHelpers.CreateOwinContext();

            await subject.Invoke(context);

            var storedState = ExtractRequestState(options.DataProtector, context);

            storedState.ReturnUrl.Should().Be(returnUrl);
        }
예제 #5
0
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke()
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true);

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

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            context.Request.Scheme   = "http";
            context.Request.Host     = new HostString("sp-internal.example.com");
            context.Request.PathBase = new PathString("/InternalPath");
            context.Request.Path     = new PathString("/LoggedOut");

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
            }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/logout?SAMLRequest");

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1]
                              .Replace('_', '/').Replace('-', '+').Replace('.', '=');

            var returnUrl = Encoding.UTF8.GetString(options.DataProtector.Unprotect(
                                                        Convert.FromBase64String(cookieValue)));

            returnUrl.Should().Be("https://sp.example.com/ExternalPath/LoggedOut");
        }
예제 #6
0
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_UsesAuthPropsReturnUrl()
        {
            var authPropsReturnUrl = "http://sp.exmample.com/AuthPropsLogout";

            var revoke = new AuthenticationResponseRevoke(
                new string[0],
                new AuthenticationProperties {
                RedirectUri = authPropsReturnUrl
            });

            var options = new KentorAuthServicesAuthenticationOptions(true);

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

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            context.Response.Headers["Location"] = "http://sp.example.com/locationHeader";

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
            }, "Federation"));

            await subject.Invoke(context);

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1];

            var returnUrl = new StoredRequestState(options.DataProtector.Unprotect(
                                                       HttpRequestData.GetBinaryData(cookieValue))).ReturnUrl;

            returnUrl.Should().Be(authPropsReturnUrl);
        }
예제 #7
0
        public async Task KentorAuthServicesAuthenticationMiddleware_MetadataWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();

            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices");

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                null,
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            await middleware.Invoke(context);

            context.Response.Body.Seek(0, SeekOrigin.Begin);

            context.Response.ContentType.Should().Contain("application/samlmetadata+xml");

            var xmlData = XDocument.Load(context.Response.Body);

            xmlData.Document.Root.Name.Should().Be(Saml2Namespaces.Saml2Metadata + "EntityDescriptor");
        }
예제 #8
0
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUrl = "http://sp.example.com/returnurl";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                                           new string[] { "KentorAuthServices" }, new AuthenticationProperties()
            {
                RedirectUri = returnUrl
            })),
                CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            StoredRequestState storedAuthnData;

            PendingAuthnRequests.TryRemove(ExtractRelayState(context), out storedAuthnData);

            storedAuthnData.ReturnUrl.Should().Be(returnUrl);
        }
예제 #9
0
        private async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_PreservesRedirect(
            string location, string expectedUrl, string path = "/Account/LogOut", AuthenticationProperties authProps = null)
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true);

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

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            context.Request.Scheme               = "http";
            context.Request.Host                 = new HostString("sp-internal.example.com");
            context.Request.PathBase             = new PathString("/AppPath");
            context.Request.Path                 = new PathString(path);
            context.Response.Headers["Location"] = location;

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
            }, "Federation"));

            await subject.Invoke(context);

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1];

            var returnUrl = new StoredRequestState(options.DataProtector.Unprotect(
                                                       HttpRequestData.GetBinaryData(cookieValue))).ReturnUrl;

            returnUrl.Should().Be(expectedUrl);
        }
예제 #10
0
        public async Task KentorAuthServicesAuthenticationMiddleware_DoesntRedirectOnUnspecifiedAuthRevoke_WhenPassive()
        {
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: new AuthenticationResponseRevoke(new string[0])),
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true)
            {
                AuthenticationMode = AuthenticationMode.Passive
            });

            var context = OwinTestHelpers.CreateOwinContext();

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
            }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUri = "http://sp.example.com/returnuri";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                                           new string[] { "KentorAuthServices" }, new AuthenticationProperties()
            {
                RedirectUri = returnUri
            })),
                CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions());

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            var requestId = AuthnRequestHelper.GetRequestId(new Uri(context.Response.Headers["Location"]));

            StoredRequestState storedAuthnData;

            PendingAuthnRequests.TryRemove(new System.IdentityModel.Tokens.Saml2Id(requestId), out storedAuthnData);

            storedAuthnData.ReturnUri.Should().Be(returnUri);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_DoesntAugmentsGeneratedClaimsWhenNameIdIsMissing()
        {
            var context = OwinTestHelpers.CreateOwinContext();

            string[] specifiedAuthTypes = null;

            context.Set<AuthenticateDelegate>("security.Authenticate",
                (authTypes, callback, state) =>
                {
                    specifiedAuthTypes = authTypes;
                    callback(new ClaimsIdentity(new Claim[]
                        {
                            new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "http://idp.example.com"),
                            new Claim(ClaimTypes.Role, "SomeRole", null, "http://idp.example.com")
                        }, "Federation"),
                        new Dictionary<string, string>(),
                        new Dictionary<string, object>(),
                        state);
                    return Task.FromResult(0);
                });

            var options = new KentorAuthServicesAuthenticationOptions(true);

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, grant: new AuthenticationResponseGrant(
                    new ClaimsIdentity(new Claim[]
                    {
                        new Claim(ClaimTypes.NameIdentifier, "ApplicationNameId")
                    }, "ApplicationIdentity"), new AuthenticationProperties())),
                CreateAppBuilder(),
                options);

            await subject.Invoke(context);

            specifiedAuthTypes.Should().HaveCount(1)
                .And.Subject.Single().Should().Be(DefaultSignInAsAuthenticationType);

            var expected = new ClaimsIdentity(new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, "ApplicationNameId"),
            }, "ApplicationIdentity");

            context.Authentication.AuthenticationResponseGrant.Identity
                .ShouldBeEquivalentTo(expected, opt => opt.IgnoringCyclicReferences());
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                new Uri("http://localhost/LoggedIn"),
                new Saml2Id(MethodBase.GetCurrentMethod().Name + "RequestID"),
                new AuthenticationProperties());

            ((AuthenticationProperties)state.RelayData).RedirectUri = state.ReturnUrl.OriginalString;
            ((AuthenticationProperties)state.RelayData).Dictionary["Test"] = "TestValue";

            var relayState = RelayStateGenerator.CreateSecureKey();

            PendingAuthnRequests.Add(relayState, state);

            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=""" + MethodBase.GetCurrentMethod().Name + @"RequestID"" >
                <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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
                new KeyValuePair<string, string>("RelayState",relayState)
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                new ClaimsIdentity(signInAsAuthenticationType) };
            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", 
                null, "ClaimsAuthenticationManagerStub"));

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                StubFactory.CreateOwinOptions());

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
                .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
                .Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
                .Should().Be("TestValue");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke()
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true);
            ((SPOptions)options.SPOptions).PublicOrigin = new Uri("https://sp.example.com/ExternalPath/");

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Scheme = "http";
            context.Request.Host = new HostString("sp-internal.example.com");
            context.Request.PathBase = new PathString("/InternalPath");
            context.Request.Path = new PathString("/LoggedOut");

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/logout?SAMLRequest");
            var returnUrl = ExtractRequestState(options.DataProtector, context).ReturnUrl;

            returnUrl.Should().Be("https://sp.example.com/ExternalPath/LoggedOut");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_LogoutsOnLogoutRequest()
        {
            var options = new KentorAuthServicesAuthenticationOptions(true);
            var subject = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(), options);

            var context = OwinTestHelpers.CreateOwinContext();

            var request = new Saml2LogoutRequest()
            {
                SessionIndex = "SessionId",
                DestinationUrl = new Uri("http://sp.example.com/AuthServices/Logout"),
                NameId = new Saml2NameIdentifier("NameId"),
                Issuer = new EntityId("https://idp.example.com"),
                SigningCertificate = SignedXmlHelper.TestCert
            };

            var url = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                .Bind(request).Location;

            context.Request.Path = new PathString(url.AbsolutePath);
            context.Request.QueryString = new QueryString(url.Query.TrimStart('?'));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/logout?SAMLResponse");

            context.Authentication.AuthenticationResponseRevoke.Should().NotBeNull();
            context.Authentication.AuthenticationResponseRevoke.AuthenticationTypes
                .Should().BeEmpty();
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectoToSecondIdp_OwinEnvironment()
        {
            var secondIdp = Options.FromConfiguration.IdentityProviders[1];
            var secondDestination = secondIdp.SingleSignOnServiceUrl;
            var secondEntityId = secondIdp.EntityId;

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties())),
                        CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();
            context.Environment["KentorAuthServices.idp"] = secondEntityId;
            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith(secondDestination.ToString());
        }
        public async Task KentorAuthServicesAuthenicationMiddleware_StoresAuthenticationProperties()
        {
            var returnUrl = "http://sp.example.com/returnurl";

            var prop = new AuthenticationProperties()
            {
                RedirectUri = returnUrl
            };
            prop.Dictionary["test"] = "SomeValue";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, prop)),
                    CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            var relayState = ExtractRelayState(context);

            StoredRequestState storedAuthnData;
            PendingAuthnRequests.TryRemove(relayState, out storedAuthnData);

            ((AuthenticationProperties)storedAuthnData.RelayData).Dictionary["test"].Should().Be("SomeValue");
        }
예제 #18
0
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();

            context.Request.Method = "POST";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                                               new Uri("http://localhost/LoggedIn"),
                                               new AuthenticationProperties());

            ((AuthenticationProperties)state.RelayData).RedirectUri        = state.ReturnUrl.OriginalString;
            ((AuthenticationProperties)state.RelayData).Dictionary["Test"] = "TestValue";

            PendingAuthnRequests.Add(new Saml2Id(MethodBase.GetCurrentMethod().Name + @"RequestID"), state);

            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=""" + MethodBase.GetCurrentMethod().Name + @"RequestID"" >
                <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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair <string, string>[] {
                new KeyValuePair <string, string>("SAMLResponse",
                                                  Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response))))
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body        = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host        = new HostString("localhost");
            context.Request.Path        = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                                             new ClaimsIdentity(signInAsAuthenticationType) };

            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager",
                                      null, "ClaimsAuthenticationManagerStub"));

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                                                                            StubFactory.CreateOwinOptions());

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
            .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
            .Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
            .Should().Be("TestValue");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_NoRedirectOnNon401()
        {
            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, null)), CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
            context.Response.Headers["Location"].Should().BeNull();
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_Acs_HonorsCommandResultHandled()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            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"">
                <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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] {
                new KeyValuePair<string, string>("SAMLResponse",
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var options = StubFactory.CreateOwinOptions();
            options.Notifications.AcsCommandResultCreated = (cr, r) =>
            {
                cr.HandledResult = true;
            };

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                null, CreateAppBuilder(), options);

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_UsesAuthPropsReturnUrl()
        {
            var authPropsReturnUrl = "http://sp.exmample.com/AuthPropsLogout";

            var revoke = new AuthenticationResponseRevoke(
                new string[0],
                new AuthenticationProperties { RedirectUri = authPropsReturnUrl });

            var options = new KentorAuthServicesAuthenticationOptions(true);
            options.SPOptions.PublicOrigin = new Uri("https://sp.example.com/ExternalPath/");

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Response.Headers["Location"] = "http://sp.example.com/locationHeader";
            context.Request.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"));

            await subject.Invoke(context);

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1];

            var returnUrl = new StoredRequestState(options.DataProtector.Unprotect(
                HttpRequestData.GetBinaryData(cookieValue))).ReturnUrl;

            returnUrl.Should().Be(authPropsReturnUrl);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            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 = ""KentorAuthServicesAuthenticationMiddleware_AcsWorks"" 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=""KentorAuthServicesAuthenticationMiddleware_AcsWorks_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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response))))
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/Saml2AuthenticationModule/acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                new ClaimsIdentity(signInAsAuthenticationType) };
            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", 
                null, "ClaimsAuthenticationManagerMock"));

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions()
                {
                    SignInAsAuthenticationType = "AuthType"
                });

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities.ShouldBeEquivalentTo(ids,
                opt => opt.IgnoringCyclicReferences());
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUri = "http://sp.example.com/returnuri";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties()
                    {
                        RedirectUri = returnUri
                    })),
                    CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions());

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            var requestId = AuthnRequestHelper.GetRequestId(new Uri(context.Response.Headers["Location"]));

            StoredRequestState storedAuthnData;
            PendingAuthnRequests.TryRemove(new System.IdentityModel.Tokens.Saml2Id(requestId), out storedAuthnData);

            storedAuthnData.ReturnUri.Should().Be(returnUri);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectoToSecondIdp_AuthenticationProperties()
        {
            var secondIdp = IdentityProvider.ActiveIdentityProviders.Skip(1).First();
            var secondDestination = secondIdp.AssertionConsumerServiceUrl;
            var secondEntityId = secondIdp.EntityId;

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties(
                        new Dictionary<string, string>()
                        {
                            { "idp", secondEntityId.Id }
                        }))), 
                        CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions());

            var context = OwinTestHelpers.CreateOwinContext();
            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().StartWith(secondDestination.ToString());
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            var authProps = new AuthenticationProperties()
            {
                IssuedUtc = new DateTime(1975, 05, 05, 05, 05, 05, DateTimeKind.Utc)
            };
            authProps.Dictionary["Test"] = "TestValue";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                new Uri("http://localhost/LoggedIn"),
                new Saml2Id("InResponseToId"),
                authProps.Dictionary);

            var relayState = SecureKeyGenerator.CreateRelayState();

            var cookieData = HttpRequestData.ConvertBinaryData(
                CreateAppBuilder().CreateDataProtector(
                    typeof(KentorAuthServicesAuthenticationMiddleware).FullName)
                    .Protect(state.Serialize()));

            context.Request.Headers["Cookie"] = $"Kentor.{relayState}={cookieData}";

            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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
                new KeyValuePair<string, string>("RelayState",relayState)
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                new ClaimsIdentity(signInAsAuthenticationType) };
            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager", 
                null, "ClaimsAuthenticationManagerStub"));

            var subject = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                StubFactory.CreateOwinOptions());

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");
            context.Response.Headers["Set-Cookie"].Should().Be($"Kentor.{relayState}=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
                .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
                .Should().Be("http://localhost/LoggedIn", 
                "the StoredRequestState.ReturnUrl should overtake the value in the AuthProperties and be stored in the AuthProps");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
                .Should().Be("TestValue");

            context.Authentication.AuthenticationResponseGrant.Properties.IssuedUtc
                .Should().Be(authProps.IssuedUtc);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUrl = "http://sp.example.com/returnurl";

            var options = new KentorAuthServicesAuthenticationOptions(true);
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties()
                    {
                        RedirectUri = returnUrl
                    })),
                    CreateAppBuilder(), options);

            var context = OwinTestHelpers.CreateOwinContext();

            await subject.Invoke(context);

            var storedState = ExtractRequestState(options.DataProtector, context);

            storedState.ReturnUrl.Should().Be(returnUrl);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_AuthRevoke_HonorsCommandResultHandled()
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true)
            {
                Notifications = new KentorAuthServicesNotifications
                {
                    LogoutCommandResultCreated = cr =>
                    {
                        cr.HandledResult = true;
                    }
                }
            };

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Scheme = "http";
            context.Request.Host = new HostString("sp-internal.example.com");
            context.Request.PathBase = new PathString("/InternalPath");
            context.Request.Path = new PathString("/LoggedOut");
            context.Request.User = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_SignInUrlRedirectsToIdp()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Host = new HostString("localhost");
            var signinPath = "/AuthServices/SignIn";
            context.Request.Path = new PathString(signinPath);
            context.Request.QueryString = new QueryString("ReturnUrl=%2FHome&idp=https%3A%2F%2Fidp2.example.com");

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp2.example.com/idp?SAMLRequest");

            var relayState = ExtractRelayState(context);

            StoredRequestState storedAuthnData;
            PendingAuthnRequests.TryRemove(relayState, out storedAuthnData);

            storedAuthnData.ReturnUrl.Should().Be("http://localhost/Home");
        }
예제 #29
0
        public async Task KentorAuthServicesAuthenticationMiddleware_AcsWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();

            context.Request.Method = "POST";

            var authProps = new AuthenticationProperties()
            {
                IssuedUtc = new DateTime(1975, 05, 05, 05, 05, 05, DateTimeKind.Utc)
            };

            authProps.Dictionary["Test"] = "TestValue";

            var state = new StoredRequestState(new EntityId("https://idp.example.com"),
                                               new Uri("http://localhost/LoggedIn"),
                                               new Saml2Id("InResponseToId"),
                                               authProps.Dictionary);

            var relayState = SecureKeyGenerator.CreateRelayState();

            var cookieData = HttpRequestData.ConvertBinaryData(
                CreateAppBuilder().CreateDataProtector(
                    typeof(KentorAuthServicesAuthenticationMiddleware).FullName)
                .Protect(state.Serialize()));

            context.Request.Headers["Cookie"] = $"Kentor.{relayState}={cookieData}";

            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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair <string, string>[] {
                new KeyValuePair <string, string>("SAMLResponse",
                                                  Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
                new KeyValuePair <string, string>("RelayState", relayState)
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body        = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host        = new HostString("localhost");
            context.Request.Path        = new PathString("/AuthServices/Acs");

            var signInAsAuthenticationType = "AuthType";
            var ids = new ClaimsIdentity[] { new ClaimsIdentity(signInAsAuthenticationType),
                                             new ClaimsIdentity(signInAsAuthenticationType) };

            ids[0].AddClaim(new Claim(ClaimTypes.NameIdentifier, "SomeUser", null, "https://idp.example.com"));
            ids[1].AddClaim(new Claim(ClaimTypes.Role, "RoleFromClaimsAuthManager",
                                      null, "ClaimsAuthenticationManagerStub"));

            var subject = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                                                                         StubFactory.CreateOwinOptions());

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");
            context.Response.Headers["Set-Cookie"].Should().Be($"Kentor.{relayState}=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT");

            context.Authentication.AuthenticationResponseGrant.Principal.Identities
            .ShouldBeEquivalentTo(ids, opt => opt.IgnoringCyclicReferences());

            context.Authentication.AuthenticationResponseGrant.Properties.RedirectUri
            .Should().Be("http://localhost/LoggedIn",
                         "the StoredRequestState.ReturnUrl should overtake the value in the AuthProperties and be stored in the AuthProps");

            context.Authentication.AuthenticationResponseGrant.Properties.Dictionary["Test"]
            .Should().Be("TestValue");

            context.Authentication.AuthenticationResponseGrant.Properties.IssuedUtc
            .Should().Be(authProps.IssuedUtc);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_LogoutRequest_HonorsCommandResultHandled()
        {
            var options = new KentorAuthServicesAuthenticationOptions(true)
            {
                Notifications = new KentorAuthServicesNotifications
                {
                    LogoutCommandResultCreated = cr =>
                    {
                        cr.HandledResult = true;
                    }
                }
            };

            var subject = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(), options);

            var context = OwinTestHelpers.CreateOwinContext();

            var request = new Saml2LogoutRequest()
            {
                SessionIndex = "SessionId",
                DestinationUrl = new Uri("http://sp.example.com/AuthServices/Logout"),
                NameId = new Saml2NameIdentifier("NameId"),
                Issuer = new EntityId("https://idp.example.com"),
                SigningCertificate = SignedXmlHelper.TestCert
            };

            var url = Saml2Binding.Get(Saml2BindingType.HttpRedirect)
                .Bind(request).Location;

            context.Request.Path = new PathString(url.AbsolutePath);
            context.Request.QueryString = new QueryString(url.Query.TrimStart('?'));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_NoRedirectWithoutChallenge()
        {
            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, null), CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(401);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_DoesntRedirectOnUnspecifiedAuthRevoke_WhenPassiveAndStrictCompatibility()
        {
            var options = new KentorAuthServicesAuthenticationOptions(true)
            {
                AuthenticationMode = AuthenticationMode.Passive,
            };
            options.SPOptions.Compatibility.StrictOwinAuthenticationMode = true;

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: new AuthenticationResponseRevoke(new string[0])),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_RedirectRemembersReturnPath()
        {
            var returnUrl = "http://sp.example.com/returnurl";

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties()
                    {
                        RedirectUri = returnUrl
                    })),
                    CreateAppBuilder(), new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            StoredRequestState storedAuthnData;
            PendingAuthnRequests.TryRemove(ExtractRelayState(context), out storedAuthnData);

            storedAuthnData.ReturnUrl.Should().Be(returnUrl);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_HandlesLogoutResponse()
        {
            var app = CreateAppBuilder();
            var options = new KentorAuthServicesAuthenticationOptions(true);
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                null,
                app,
                options);

            var context = OwinTestHelpers.CreateOwinContext();

            var relayState = "MyRelayState";
            var response = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl = new Uri("https://sp.example.com/AuthServices/Logout"),
                RelayState = relayState,
                SigningCertificate = SignedXmlHelper.TestCert,
                Issuer = new EntityId("https://idp.example.com")
            };
            var requestUri = Saml2Binding.Get(Saml2BindingType.HttpRedirect).Bind(response).Location;

            var cookieData = HttpRequestData.EscapeBase64CookieValue(
                Convert.ToBase64String(
                    options.DataProtector.Protect(
                        Encoding.UTF8.GetBytes("http://loggedout.example.com/"))));
            context.Request.Headers["Cookie"] = $"Kentor.{relayState}={cookieData}";
            context.Request.Path = new PathString(requestUri.AbsolutePath);
            context.Request.QueryString = new QueryString(requestUri.Query.TrimStart('?'));
            
            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().Be("http://loggedout.example.com/");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_UsesCommandResultLocation()
        {
            // For Owin middleware, the redirect uri is part of the
            // authentication properties, but we don't want to use it as it
            // is because it can be empty (e.g. on unsolicited responses
            // or until #182 is fixed). The redirect uri should be taken
            // from the commandresult location instead.

            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            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"">
                <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:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] { 
                new KeyValuePair<string, string>("SAMLResponse", 
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response))))
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var middleware = new KentorAuthServicesAuthenticationMiddleware(null, CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true)
                {
                    SignInAsAuthenticationType = "AuthType"
                });

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(302);
            context.Response.Headers["Location"].Should().Be("http://localhost/LoggedIn");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_Acs_HonorsSessionNotOnOrAfter()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Method = "POST";

            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"">
                <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:AuthnStatement AuthnInstant=""{DateTime.UtcNow.ToSaml2DateTimeString()}"" SessionNotOnOrAfter=""2050-01-01T00:00:00Z"">
                        <saml2:AuthnContext>
                            <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
                        </saml2:AuthnContext>
                    </saml2:AuthnStatement>
                </saml2:Assertion>
            </saml2p:Response>";

            var bodyData = new KeyValuePair<string, string>[] {
                new KeyValuePair<string, string>("SAMLResponse",
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(SignedXmlHelper.SignXml(response)))),
            };

            var encodedBodyData = new FormUrlEncodedContent(bodyData);

            context.Request.Body = encodedBodyData.ReadAsStreamAsync().Result;
            context.Request.ContentType = encodedBodyData.Headers.ContentType.ToString();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices/Acs");

            var options = StubFactory.CreateOwinOptions();

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                null, CreateAppBuilder(), options);

            await subject.Invoke(context);

            context.Authentication.AuthenticationResponseGrant.Properties
                .AllowRefresh.Should().BeFalse("AllowRefresh should be false if SessionNotOnOrAfter is specified");
            context.Authentication.AuthenticationResponseGrant.Properties
                .ExpiresUtc.Should().BeCloseTo(
                new DateTimeOffset(2050, 1, 1, 0, 0, 0, new TimeSpan(0)),
                because: "SessionNotOnOrAfter should be honored.");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_MetadataWorks()
        {
            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Host = new HostString("localhost");
            context.Request.Path = new PathString("/AuthServices");

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                null,
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            await middleware.Invoke(context);
            context.Response.Body.Seek(0, SeekOrigin.Begin);

            context.Response.ContentType.Should().Contain("application/samlmetadata+xml");

            var xmlData = XDocument.Load(context.Response.Body);

            xmlData.Document.Root.Name.Should().Be(Saml2Namespaces.Saml2Metadata + "EntityDescriptor");
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_DoesntRedirectOnUnSpecificAuthChallenge_WhenPassive()
        {
            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[0], null)), CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true)
                { AuthenticationMode = AuthenticationMode.Passive });

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(401);
        }
        public void KentorAuthServicesAuthenticationMiddleware_WorksOnNullDiscoveryResponseUrl()
        {
            var context = OwinTestHelpers.CreateOwinContext();

            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, null),
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(false)
                {
                    SPOptions = new SPOptions()
                    {
                        EntityId = new EntityId("http://localhost/metadata")
                    }
                });

            Func<Task> f = async () => await middleware.Invoke(context);

            f.ShouldNotThrow();
        }
        private async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnAuthRevoke_PreservesRedirect(
            string location, string expectedUrl, string path = "/Account/LogOut")
        {
            var revoke = new AuthenticationResponseRevoke(new string[0]);

            var options = new KentorAuthServicesAuthenticationOptions(true);
            ((SPOptions)options.SPOptions).PublicOrigin = new Uri("https://sp.example.com/ExternalPath/");

            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(303, revoke: revoke),
                CreateAppBuilder(),
                options);

            var context = OwinTestHelpers.CreateOwinContext();
            context.Request.Scheme = "http";
            context.Request.Host = new HostString("sp-internal.example.com");
            context.Request.PathBase = new PathString("/AppPath");
            context.Request.Path = new PathString(path);
            context.Response.Headers["Location"] = location;

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            var cookieValue = context.Response.Headers["Set-Cookie"].Split(';', '=')[1]
                .Replace('_', '/').Replace('-', '+').Replace('.', '=');

            var returnUrl = Encoding.UTF8.GetString(options.DataProtector.Unprotect(
                Convert.FromBase64String(cookieValue)));

            returnUrl.Should().Be(expectedUrl);
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesPostOnAuthChallenge()
        {
            var middleware = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(401, new AuthenticationResponseChallenge(
                    new string[] { "KentorAuthServices" }, new AuthenticationProperties(
                        new Dictionary<string, string>()
                        {
                            { "idp", "http://localhost:13428/idpMetadata" }
                        }))),
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true));

            var context = OwinTestHelpers.CreateOwinContext();

            await middleware.Invoke(context);

            context.Response.StatusCode.Should().Be(200);
            context.Response.Body.Seek(0, SeekOrigin.Begin);

            // Fix to #295, where content length is incorrectly set to 0 by the
            // next middleware. It appears as it works if the content length is
            // simply removed. See discussion in GitHub issue #295.
            context.Response.ContentLength.Should().NotHaveValue();

            using (var reader = new StreamReader(context.Response.Body))
            {
                string bodyContent = reader.ReadToEnd();

                // Checking some random stuff in body to make sure it looks like a SAML Post.
                bodyContent.Should().Contain("<form action");
                bodyContent.Should().Contain("<input type=\"hidden\" name=\"SAMLRequest\"");
            }
        }
        public async Task KentorAuthServicesAuthenticationMiddleware_CreatesRedirectOnSpecifiedAuthRevoke_WhenPassive()
        {
            var subject = new KentorAuthServicesAuthenticationMiddleware(
                new StubOwinMiddleware(200, revoke: new AuthenticationResponseRevoke(
                    new string[] { "KentorAuthServices" })),
                CreateAppBuilder(),
                new KentorAuthServicesAuthenticationOptions(true)
                {
                    AuthenticationMode = AuthenticationMode.Passive
                });

            var context = OwinTestHelpers.CreateOwinContext();

            Thread.CurrentPrincipal = new ClaimsPrincipal(
                new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "NameId", null, "https://idp.example.com"),
                    new Claim(AuthServicesClaimTypes.SessionIndex, "SessionId", null, "https://idp.example.com")
                }, "Federation"));

            await subject.Invoke(context);

            context.Response.StatusCode.Should().Be(303);
            context.Response.Headers["Location"].Should().StartWith("https://idp.example.com/logout?SAMLRequest");
        }