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"); }
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")); }
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"); }
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()); }
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")); }
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")); }
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("/"); }
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); }
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); }
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); }
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); }