Exemple #1
0
        public void Saml2Urls_Ctor_AllowsNullAcs()
        {
            // AssertionConsumerServiceURL is optional in the SAML spec
            var subject = new Saml2Urls(null, new Uri("http://localhost/signin"), null);

            subject.AssertionConsumerServiceUrl.Should().Be(null);
            subject.SignInUrl.ToString().Should().Be("http://localhost/signin");
        }
Exemple #2
0
        public void Saml2Urls_Ctor_HandlesApplicationInRoot()
        {
            var appUrl     = new Uri("http://localhost:42/");
            var modulePath = "/modulePath";

            var subject = new Saml2Urls(appUrl, modulePath);

            subject.AssertionConsumerServiceUrl.Should().Be(new Uri("http://localhost:42/modulePath/Acs"));
            subject.SignInUrl.Should().Be(new Uri("http://localhost:42/modulePath/SignIn"));
        }
Exemple #3
0
        public async Task Saml2Urls_Ctor_FromOwinHttpRequestData_PublicOrigin()
        {
            var ctx     = OwinTestHelpers.CreateOwinContext();
            var options = StubFactory.CreateOptionsPublicOrigin(new Uri("https://my.public.origin:8443/"));
            var subject = await ctx.ToHttpRequestData(null, Options.FromConfiguration.Notifications?.GetRelayState);

            var urls = new Saml2Urls(subject, options);

            urls.AssertionConsumerServiceUrl.ShouldBeEquivalentTo("https://my.public.origin:8443/Saml2/Acs");
            urls.SignInUrl.ShouldBeEquivalentTo("https://my.public.origin:8443/Saml2/SignIn");
        }
Exemple #4
0
        public void AuthServiecsUrls_Ctor_AcceptsFullUrls()
        {
            var acsUrl    = new Uri("http://localhost:73/MyApp/MyAcs");
            var signinUrl = new Uri("http://localhost:73/MyApp/MySignin");
            var appUrl    = new Uri("http://localhost:73/MyApp");

            var subject = new Saml2Urls(acsUrl, signinUrl, appUrl);

            subject.AssertionConsumerServiceUrl.ToString().Should().Be(acsUrl.ToString());
            subject.SignInUrl.ToString().Should().Be(signinUrl.ToString());
            subject.ApplicationUrl.Should().Be(appUrl.ToString());
        }
Exemple #5
0
        public void Saml2Urls_Ctor_PerRequest_PublicOrigin()
        {
            var options = StubFactory.CreateOptionsPublicOrigin(new Uri("https://my.public.origin:8443/"));

            options.Notifications.GetPublicOrigin = (requestData) =>
            {
                return(new Uri("https://special.public.origin/"));
            };
            var urls = new Saml2Urls(new HttpRequestData("get", new Uri("http://servername/")), options);

            urls.AssertionConsumerServiceUrl.Should().BeEquivalentTo(new Uri("https://special.public.origin/Saml2/Acs"));
            urls.SignInUrl.Should().BeEquivalentTo(new Uri("https://special.public.origin/Saml2/SignIn"));
        }
Exemple #6
0
        public async Task Saml2Urls_Ctor_FromOwinHttpRequestData_PublicOrigin()
        {
            var ctx     = OwinTestHelpers.CreateOwinContext();
            var options = StubFactory.CreateOptionsPublicOrigin(new Uri("https://my.public.origin:8443/"));
            var subject = await ctx.ToHttpRequestData(Substitute.For <ICookieManager>(), null);

            var urls = new Saml2Urls(subject, options);

            urls.AssertionConsumerServiceUrl.Should().BeEquivalentTo(
                new Uri("https://my.public.origin:8443/Saml2/Acs"));
            urls.SignInUrl.Should().BeEquivalentTo(
                new Uri("https://my.public.origin:8443/Saml2/SignIn"));
        }
Exemple #7
0
        public void Saml2Urls_Ctor_EnsuresApplicationUrlEndsWithSlash()
        {
            var request = new HttpRequestData(
                "GET",
                new Uri("http://localhost:1234/Foo/Bar"),
                "/Foo",
                null,
                null,
                null);

            var options = StubFactory.CreateOptions();
            var subject = new Saml2Urls(request, options);

            subject.ApplicationUrl.OriginalString.Should().EndWith("/");
        }
Exemple #8
0
        public void Saml2Urls_Ctor_FromHttpRequest_PublicOrigin()
        {
            var    url     = new Uri("http://example.com:42/ApplicationPath/Path?name=DROP%20TABLE%20STUDENTS");
            string appPath = "/ApplicationPath";
            var    request = Substitute.For <HttpRequestBase>();

            request.HttpMethod.Returns("GET");
            request.Url.Returns(url);
            request.Form.Returns(new NameValueCollection {
                { "Key", "Value" }
            });
            request.ApplicationPath.Returns(appPath);
            var options = StubFactory.CreateOptionsPublicOrigin(new Uri("https://my.public.origin:8443/OtherPath"));
            var subject = request.ToHttpRequestData();
            var urls    = new Saml2Urls(subject, options);

            urls.AssertionConsumerServiceUrl.ShouldBeEquivalentTo("https://my.public.origin:8443/OtherPath/Saml2/Acs");
            urls.SignInUrl.ShouldBeEquivalentTo("https://my.public.origin:8443/OtherPath/Saml2/SignIn");
        }
        protected async override Task ApplyResponseGrantAsync()
        {
            // Automatically sign out, even if passive because passive sign in and auto sign out
            // is typically most common scenario. Unless strict compatibility is set.
            var mode = Options.SPOptions.Compatibility.StrictOwinAuthenticationMode ?
                       Options.AuthenticationMode : AuthenticationMode.Active;

            var revoke = Helper.LookupSignOut(Options.AuthenticationType, mode);

            if (revoke != null && Context.Request.Path.Value != (Options.SPOptions.ModulePath + "/Logout"))
            {
                var request = await Context.ToHttpRequestData(Options.CookieManager, Options.DataProtector.Unprotect);

                var urls = new Saml2Urls(request, Options);

                string redirectUrl = revoke.Properties.RedirectUri;
                if (string.IsNullOrEmpty(redirectUrl))
                {
                    if (Context.Response.StatusCode / 100 == 3)
                    {
                        redirectUrl = Context.Response.Headers["Location"];
                    }
                    else
                    {
                        // ApplicationUrl is base path, after consideration taken to PublicOrigin.
                        redirectUrl = urls.ApplicationUrl.AbsolutePath + Context.Request.Path.ToString().TrimStart('/');
                    }
                }

                var result = LogoutCommand.Run(request, redirectUrl, Options);

                if (!result.HandledResult)
                {
                    result.Apply(
                        Context,
                        Options.DataProtector,
                        Options.CookieManager,
                        Options.Notifications.EmitSameSiteNone(Request.GetUserAgent()));
                }
            }

            await AugmentAuthenticationGrantWithLogoutClaims(Context);
        }
Exemple #10
0
        protected async override Task ApplyResponseGrantAsync()
        {
            // Automatically sign out, even if passive because passive sign in and auto sign out
            // is typically most common scenario. Unless strict compatibility is set.
            var mode = Options.SPOptions.Compatibility.StrictOwinAuthenticationMode ?
                       Options.AuthenticationMode : AuthenticationMode.Active;

            var revoke = Helper.LookupSignOut(Options.AuthenticationType, mode);

            if (revoke != null)
            {
                var request = await Context.ToHttpRequestData(Options.DataProtector.Unprotect);

                var urls = new Saml2Urls(request, Options);

                string redirectUrl = revoke.Properties.RedirectUri;
                if (string.IsNullOrEmpty(redirectUrl))
                {
                    if (Context.Response.StatusCode / 100 == 3)
                    {
                        redirectUrl = Context.Response.Headers["Location"];
                    }
                    else
                    {
                        redirectUrl = Context.Request.Path.ToUriComponent();
                    }
                }

                var result = LogoutCommand.Run(request, redirectUrl, Options);

                if (!result.HandledResult)
                {
                    result.Apply(Context, Options.DataProtector);
                }
            }

            await AugmentAuthenticationGrantWithLogoutClaims(Context);
        }
Exemple #11
0
        public Saml2AuthenticationRequest CreateAuthenticateRequest(
            Saml2Urls saml2Urls)
        {
            if (saml2Urls == null)
            {
                throw new ArgumentNullException(nameof(saml2Urls));
            }

            var authnRequest = new Saml2AuthenticationRequest()
            {
                DestinationUrl = SingleSignOnServiceUrl,
                AssertionConsumerServiceUrl = saml2Urls.AssertionConsumerServiceUrl,
                Issuer = spOptions.EntityId,
                // For now we only support one attribute consuming service.
                AttributeConsumingServiceIndex = spOptions.AttributeConsumingServices.Any() ? 0 : (int?)null,
                NameIdPolicy          = spOptions.NameIdPolicy,
                RequestedAuthnContext = spOptions.RequestedAuthnContext,
                SigningAlgorithm      = this.OutboundSigningAlgorithm
            };

            if (spOptions.AuthenticateRequestSigningBehavior == SigningBehavior.Always ||
                (spOptions.AuthenticateRequestSigningBehavior == SigningBehavior.IfIdpWantAuthnRequestsSigned &&
                 WantAuthnRequestsSigned))
            {
                if (spOptions.SigningServiceCertificate == null)
                {
                    throw new ConfigurationErrorsException(
                              string.Format(
                                  CultureInfo.InvariantCulture,
                                  "Idp \"{0}\" is configured for signed AuthenticateRequests, but ServiceCertificates configuration contains no certificate with usage \"Signing\" or \"Both\". To resolve this issue you can a) add a service certificate with usage \"Signing\" or \"Both\" (default if not specified is \"Both\") or b) Set the AuthenticateRequestSigningBehavior configuration property to \"Never\".",
                                  EntityId.Id));
                }

                authnRequest.SigningCertificate = spOptions.SigningServiceCertificate;
            }

            return(authnRequest);
        }
        public static ExtendedEntityDescriptor CreateMetadata(this SPOptions spOptions, Saml2Urls urls)
        {
            var ed = new ExtendedEntityDescriptor
            {
                EntityId      = spOptions.EntityId,
                Organization  = spOptions.Organization,
                CacheDuration = spOptions.MetadataCacheDuration,
            };

            if (spOptions.MetadataValidDuration.HasValue)
            {
                ed.ValidUntil = DateTime.UtcNow.Add(spOptions.MetadataValidDuration.Value);
            }

            foreach (var contact in spOptions.Contacts)
            {
                ed.Contacts.Add(contact);
            }

            var spsso = new ExtendedServiceProviderSingleSignOnDescriptor()
            {
                WantAssertionsSigned         = spOptions.WantAssertionsSigned,
                AuthenticationRequestsSigned = spOptions.AuthenticateRequestSigningBehavior == SigningBehavior.Always
            };

            spsso.ProtocolsSupported.Add(new Uri("urn:oasis:names:tc:SAML:2.0:protocol"));

            spsso.AssertionConsumerServices.Add(0, new IndexedProtocolEndpoint()
            {
                Index     = 0,
                IsDefault = true,
                Binding   = Saml2Binding.HttpPostUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            spsso.AssertionConsumerServices.Add(1, new IndexedProtocolEndpoint()
            {
                Index     = 1,
                IsDefault = false,
                Binding   = Saml2Binding.HttpArtifactUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            foreach (var attributeService in spOptions.AttributeConsumingServices)
            {
                spsso.AttributeConsumingServices.Add(attributeService);
            }

            if (spOptions.ServiceCertificates != null)
            {
                var publishCertificates = spOptions.MetadataCertificates;
                foreach (var serviceCert in publishCertificates)
                {
                    using (var securityToken = new X509SecurityToken(serviceCert.Certificate))
                    {
                        spsso.Keys.Add(
                            new KeyDescriptor
                        {
                            Use     = (KeyType)(byte)serviceCert.Use,
                            KeyInfo = new SecurityKeyIdentifier(securityToken.CreateKeyIdentifierClause <X509RawDataKeyIdentifierClause>())
                        }
                            );
                    }
                }
            }

            if (spOptions.SigningServiceCertificate != null)
            {
                spsso.SingleLogoutServices.Add(new ProtocolEndpoint(
                                                   Saml2Binding.HttpRedirectUri, urls.LogoutUrl));
                spsso.SingleLogoutServices.Add(new ProtocolEndpoint(
                                                   Saml2Binding.HttpPostUri, urls.LogoutUrl));
            }

            if (spOptions.DiscoveryServiceUrl != null &&
                !string.IsNullOrEmpty(spOptions.DiscoveryServiceUrl.OriginalString))
            {
                spsso.Extensions.DiscoveryResponse = new IndexedProtocolEndpoint
                {
                    Binding   = Saml2Binding.DiscoveryResponseUri,
                    Index     = 0,
                    IsDefault = true,
                    Location  = urls.SignInUrl
                };
            }

            ed.RoleDescriptors.Add(spsso);

            return(ed);
        }
Exemple #13
0
        public static EntityDescriptor CreateMetadata(this SPOptions spOptions, Saml2Urls urls)
        {
            var ed = new EntityDescriptor
            {
                EntityId      = spOptions.EntityId,
                Organization  = spOptions.Organization,
                CacheDuration = spOptions.MetadataCacheDuration,
            };

            if (spOptions.MetadataValidDuration.HasValue)
            {
                ed.ValidUntil = DateTime.UtcNow.Add(spOptions.MetadataValidDuration.Value);
            }

            foreach (var contact in spOptions.Contacts)
            {
                ed.Contacts.Add(contact);
            }

            var spsso = new SpSsoDescriptor()
            {
                WantAssertionsSigned = spOptions.WantAssertionsSigned,
                AuthnRequestsSigned  = spOptions.AuthenticateRequestSigningBehavior == SigningBehavior.Always
            };

            spsso.ProtocolsSupported.Add(new Uri("urn:oasis:names:tc:SAML:2.0:protocol"));

            spsso.AssertionConsumerServices.Add(0, new AssertionConsumerService()
            {
                Index     = 0,
                IsDefault = true,
                Binding   = Saml2Binding.HttpPostUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            spsso.AssertionConsumerServices.Add(1, new AssertionConsumerService()
            {
                Index     = 1,
                IsDefault = false,
                Binding   = Saml2Binding.HttpArtifactUri,
                Location  = urls.AssertionConsumerServiceUrl
            });

            foreach (var attributeService in spOptions.AttributeConsumingServices)
            {
                spsso.AttributeConsumingServices.Add(attributeService.Index, attributeService);
            }

            if (spOptions.ServiceCertificates != null)
            {
                var publishCertificates = spOptions.MetadataCertificates;
                foreach (var serviceCert in publishCertificates)
                {
                    var x509Data = new X509Data();
                    x509Data.Certificates.Add(serviceCert.Certificate);
                    var keyInfo = new DSigKeyInfo();
                    keyInfo.Data.Add(x509Data);

                    spsso.Keys.Add(
                        new KeyDescriptor
                    {
                        Use     = (KeyType)(byte)serviceCert.Use,
                        KeyInfo = keyInfo
                    }
                        );
                }
            }

            if (spOptions.SigningServiceCertificate != null)
            {
                spsso.SingleLogoutServices.Add(new SingleLogoutService(
                                                   Saml2Binding.HttpRedirectUri, urls.LogoutUrl));

                if (spOptions.Compatibility.EnableLogoutOverPost)
                {
                    spsso.SingleLogoutServices.Add(new SingleLogoutService(
                                                       Saml2Binding.HttpPostUri, urls.LogoutUrl));
                }
            }

            if (spOptions.DiscoveryServiceUrl != null &&
                !string.IsNullOrEmpty(spOptions.DiscoveryServiceUrl.OriginalString))
            {
                spsso.DiscoveryResponses.Add(0, new DiscoveryResponse
                {
                    Binding   = Saml2Binding.DiscoveryResponseUri,
                    Index     = 0,
                    IsDefault = true,
                    Location  = urls.SignInUrl
                });
            }

            ed.RoleDescriptors.Add(spsso);

            return(ed);
        }