Ejemplo n.º 1
0
        private static CommandResult RedirectToDiscoveryService(
            string returnPath,
            SPOptions spOptions,
            Saml2Urls saml2Urls,
            IDictionary <string, string> relayData)
        {
            string returnUrl = saml2Urls.SignInUrl.OriginalString;

            var relayState = SecureKeyGenerator.CreateRelayState();

            returnUrl += "?RelayState=" + Uri.EscapeDataString(relayState);

            var redirectLocation = string.Format(
                CultureInfo.InvariantCulture,
                "{0}?entityID={1}&return={2}&returnIDParam=idp",
                spOptions.DiscoveryServiceUrl,
                Uri.EscapeDataString(spOptions.EntityId.Id),
                Uri.EscapeDataString(returnUrl));

            var requestState = new StoredRequestState(
                null,
                returnPath == null ? null : new Uri(returnPath, UriKind.RelativeOrAbsolute),
                null,
                relayData);

            return(new CommandResult()
            {
                HttpStatusCode = HttpStatusCode.SeeOther,
                Location = new Uri(redirectLocation),
                RequestState = requestState,
                SetCookieName = StoredRequestState.CookieNameBase + relayState
            });
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Create a SAML artifact value.
        /// </summary>
        /// <param name="issuer">Entity id of the artifact issuer.</param>
        /// <param name="endpointIndex">Index of the artifact resolution endpoint
        /// that the requester should use to resolve the artifact.</param>
        public static byte[] CreateArtifact(EntityId issuer, int endpointIndex)
        {
            if (issuer == null)
            {
                throw new ArgumentNullException(nameof(issuer));
            }

            var artifact = new byte[44];

            artifact[1] = 4; // Header is 0004

            artifact[2] = (byte)(endpointIndex >> 8);
            artifact[3] = (byte)endpointIndex;

            Array.Copy(sha1.ComputeHash(Encoding.UTF8.GetBytes(issuer.Id)),
                       0, artifact, 4, 20);

            Array.Copy(SecureKeyGenerator.CreateArtifactMessageHandle(), 0, artifact, 24, 20);

            return(artifact);
        }
Ejemplo n.º 3
0
        public void SecureKeyGenerator_CreateRelayState()
        {
            // Loop until we've seen the replacement work.
            var containedDash       = false;
            var containedUnderscore = false;

            for (int i = 0; !containedDash || !containedUnderscore; i++)
            {
                i.Should().BeLessThan(1000, because: "if replacement works, we should have found the replacement characters sooner");
                var result = SecureKeyGenerator.CreateRelayState();

                // Can't really test a random algo any better than expecting a
                // specific length of the result and the right chars.
                result.Length.Should().Be(24);

                containedDash       = containedDash || result.Contains("-");
                containedUnderscore = containedUnderscore || result.Contains("_");

                // Resulting string should not need to be URL encoded.
                result.Should().MatchRegex("^[A-Za-z0-9\\-_]*$");
            }
        }
Ejemplo n.º 4
0
        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);
        }
 /// <summary>
 /// Default constructor
 /// </summary>
 public Saml2AuthenticationRequest()
 {
     RelayState = SecureKeyGenerator.CreateRelayState();
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Ctor
 /// </summary>
 public Saml2LogoutRequest()
 {
     RelayState = SecureKeyGenerator.CreateRelayState();
 }
Ejemplo n.º 7
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 Saml2Id(MethodBase.GetCurrentMethod().Name + "RequestID"),
                                               new AuthenticationProperties());

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

            var relayState = SecureKeyGenerator.CreateRelayState();

            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");
        }
Ejemplo n.º 8
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);
        }