From 22e27b21addee769676cdb5b3a18f94ab4201261 Mon Sep 17 00:00:00 2001 From: Charley Wu Date: Tue, 26 Mar 2024 08:53:21 +0800 Subject: [PATCH 1/2] Fix SAML single logout not working --- .devcontainer/keycloak/import/demo-realm.json | 143 ++++++++++++++++-- samples/AspNetCoreSample/Program.cs | 19 ++- samples/AspNetCoreSample/appsettings.json | 6 +- .../App_Data => AspNetCoreSample}/saml.p12 | Bin 4 files changed, 149 insertions(+), 19 deletions(-) rename samples/{OwinSample/App_Data => AspNetCoreSample}/saml.p12 (100%) diff --git a/.devcontainer/keycloak/import/demo-realm.json b/.devcontainer/keycloak/import/demo-realm.json index 75ecf01b..75e600d6 100644 --- a/.devcontainer/keycloak/import/demo-realm.json +++ b/.devcontainer/keycloak/import/demo-realm.json @@ -1,6 +1,8 @@ { "id" : "d6d2a42d-e33a-493d-b150-fb09e7d48d0d", "realm" : "demo", + "displayName" : "DEMO", + "displayNameHtml" : "", "notBefore" : 0, "defaultSignatureAlgorithm" : "RS256", "revokeRefreshToken" : false, @@ -246,6 +248,7 @@ "attributes" : { } } ], "cas" : [ ], + "https://localhost:44345/Saml2/" : [ ], "security-admin-console" : [ ], "admin-cli" : [ ], "account-console" : [ ], @@ -765,6 +768,122 @@ } ], "defaultClientScopes" : [ ], "optionalClientScopes" : [ ] + }, { + "id" : "32c71ab9-7e98-4781-a13f-6db99753381e", + "clientId" : "https://localhost:44345/Saml2/", + "name" : "OwinSample", + "description" : "", + "rootUrl" : "https://localhost:44345", + "adminUrl" : "", + "baseUrl" : "/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : true, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/Saml2/Acs" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : true, + "protocol" : "saml", + "attributes" : { + "saml.assertion.signature" : "true", + "saml.force.post.binding" : "false", + "saml.encrypt" : "false", + "saml.server.signature" : "true", + "saml.server.signature.keyinfo.ext" : "false", + "saml.signing.certificate" : "MIIClzCCAX8CBgGMWViuFDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARzYW1sMB4XDTIzMTIxMTE0NDUzM1oXDTMzMTIxMTE0NDcxM1owDzENMAsGA1UEAwwEc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJv58Hu1ASYA1K+nY1qwcc9C+oOyusVn416xNeJIA1ZDXHv7d3u2jsjtScY9o/G4P04H5pikbQed6aW/BHvrgGjR9qYqC8uXiN1d0PfyfCDkOW3+2eQbTK3buC0t8ty/WtIAHfn7o0yYEx/qcZ0KIZaHbwYETux9qwVyx7UJRga1Nxgh3JTUQP9WXOAHMJGXFNQTOsqiLcaN2c+fJ71g+Js1IrT/8HKhTGb2BgAmTiT3Ly1kMrPkUpZX8MCBK8T7srVJ7nAb5I5K2wFX8zJP3QNWi6aFdLNzYQmAV/fEUx8AeKWG+1zMsOc5gSMZhhJuMLxwy/D05ySg+QWZmUXSXS8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAOacJf764zEmGh2PKKIYye0Ah9qA0TnI1ocAZP/rmADsdv/tCOblodIR+TSnaLsNjyod4oAe431ydnp/ldyOZRNn63vJjL8NGyUwqgwH3JQdMl9/rMaMr1whQn4Y2pOEOe+ajTSW0ewUYi4vTJcQ0hZssTCll/4eVUtn20vgjaMnDCHaljxC7HmrfwTNmDgbto4+3Ku2oyoEEXUCGdANx86Iq7luPu+HzJrrtD0sjKIWlXFkjAwp2Fg4hue8AABPsrHTb4MfncFZrb3hpKOXyqKeGG4OZml4QYmWVENy0ZnMmja0nuGa+0hXKLYgmhrqX+r9Qz9Kq220/E6tVCUiU9w==", + "saml.artifact.binding.identifier" : "sVil8u1JrItMkQlyKge+jpDT9k8=", + "saml.artifact.binding" : "true", + "saml.signature.algorithm" : "RSA_SHA256", + "saml_force_name_id_format" : "false", + "saml.client.signature" : "false", + "saml.authnstatement" : "true", + "display.on.consent.screen" : "false", + "saml_name_id_format" : "username", + "saml.signing.private.key" : "MIIEowIBAAKCAQEAm/nwe7UBJgDUr6djWrBxz0L6g7K6xWfjXrE14kgDVkNce/t3e7aOyO1Jxj2j8bg/TgfmmKRtB53ppb8Ee+uAaNH2pioLy5eI3V3Q9/J8IOQ5bf7Z5BtMrdu4LS3y3L9a0gAd+fujTJgTH+pxnQohlodvBgRO7H2rBXLHtQlGBrU3GCHclNRA/1Zc4AcwkZcU1BM6yqItxo3Zz58nvWD4mzUitP/wcqFMZvYGACZOJPcvLWQys+RSllfwwIErxPuytUnucBvkjkrbAVfzMk/dA1aLpoV0s3NhCYBX98RTHwB4pYb7XMyw5zmBIxmGEm4wvHDL8PTnJKD5BZmZRdJdLwIDAQABAoIBAARTjqNCdjQxfLTHQ1Ro0CysEm/PEtWBQrIbNJVAuHBO8QSdXoc8x+wfLNcwrtijFYUavKo05rNPOC5j7yy9b7PjSGCmij+M8KZslkHHukAH+eco/66PP/Vol/dk2WIxyplIQzdDuW1ZSy/XnGwl3kr4bxDEfiiazxYZGhyq6QQsPTOX+9wNJsMviTpfayP1olfbYthOCaaz02qDmR0HiHRdlF62j6sybq3ErgMT7vYZOz2sQH6Oo+2ToxZnGkJKPyQ+O/6VecKpmKL5txEXO6rM3I7+V9x2z4dyxuy3iY/u1Isd/7kXtJIGPCF2RldlBZydFEdbl6QYY1BrzZ/l22kCgYEAyGAFZyKpGqkjRwhrdItFvqb2QO4eImlJWH1FrEaCOLrh81PmAeucFpwlbseNq/kekLYZH7+so8007344L083SBazaPqCOsmdcGdzGPavCbaFQUzAqGj1hUT7mMkOrXujbEoY3ngSD5khO59jhfNnYLxAE1bC1I2N5mlnzjy6lDkCgYEAx0amH61ogZGQIx3EOGpiMXf0M57ZoF9WF4NC7piN2L8bwoyaYfIa5DmkYOVgCfrPrPYP4TLR0eo4z1qHC20hCxfhhnKBmoodEtUV7Lto839w2AUBNbQidnP+KFWJRUsOfl0vO46xniComO1AJ+2LkIQAPq2x34+VR66OT1xxDKcCgYBG3w+KJwxAzcoYebXoBsqoYE2BMbee3DaBAe3+vQGaJx97/RTBYSBYLupegF5vkTFqZb4FKLpbRV2Px8j/krku2jiizNf7CwyQkUZ4cef/O3tuWUNbTaRperiylYqHec+Xoa2iIj3hHnxOplWBL1JFONBBBtLqcxbZhDafD4O+oQKBgQCI0hwbYc+ALrZdNgHUjk5vEqIrkyRu9SZCLJCXC01RBR4FPM5+82C9VEplcPe4wmk2oxeSEnd3fi6VR92y3bGzUSk6S4Jq3etKU92i1aYgkV6kIwOKoOyMkeVuQhRm7Dq+TjKw3K9dF6VKopLLF1Ec31TftBiNm6LuPY5eNOU1vwKBgDodDXDL6HlI6v3IHeFlUqkIf8xr+qRvsmfAHfDTR3CKIAWjkJnuHtWYyfZnhyOM49yGUiXN5q4NjGjNvfzTKtV5JadPqua4onIvb+0NwbC5sFV49v21Kx0NNuSbVy9e0ewOI3myivHom5hix1FbCb9VG4iVtRb2cQZw7icoIBE7", + "saml.allow.ecp.flow" : "false", + "saml_signature_canonicalization_method" : "http://www.w3.org/2001/10/xml-exc-c14n#", + "saml.onetimeuse.condition" : "false", + "saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer" : "NONE" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "7ea90ffd-326d-4a09-a9ba-61446e3fee17", + "name" : "email", + "protocol" : "saml", + "protocolMapper" : "saml-user-property-mapper", + "consentRequired" : false, + "config" : { + "attribute.nameformat" : "Basic", + "user.attribute" : "email", + "attribute.name" : "email" + } + }, { + "id" : "19620319-42d9-4ce6-baa9-37f68ee06a02", + "name" : "given name", + "protocol" : "cas", + "protocolMapper" : "cas-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "firstName", + "claim.name" : "givenName", + "jsonType.label" : "String" + } + }, { + "id" : "9ea1e2ea-0049-40ce-9897-50f1d49aeee2", + "name" : "family name", + "protocol" : "cas", + "protocolMapper" : "cas-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "lastName", + "claim.name" : "sn", + "jsonType.label" : "String" + } + }, { + "id" : "e6806b7b-de19-4915-9ac3-9f80b1d31f56", + "name" : "full name", + "protocol" : "cas", + "protocolMapper" : "cas-full-name-mapper", + "consentRequired" : false, + "config" : { + "claim.name" : "cn", + "jsonType.label" : "String" + } + }, { + "id" : "2f6bc091-fc68-477d-b09d-f040ae2fe1b6", + "name" : "email", + "protocol" : "cas", + "protocolMapper" : "cas-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "email", + "claim.name" : "mail", + "jsonType.label" : "String" + } + }, { + "id" : "d14b1e1f-49e4-45b0-9477-4591a67fa5df", + "name" : "username", + "protocol" : "saml", + "protocolMapper" : "saml-user-property-mapper", + "consentRequired" : false, + "config" : { + "attribute.nameformat" : "Basic", + "user.attribute" : "username", + "attribute.name" : "username" + } + } ], + "defaultClientScopes" : [ ], + "optionalClientScopes" : [ ] }, { "id" : "0a520b4c-2073-4e21-97f8-b9aa043cfada", "clientId" : "https://localhost:5001/Saml2/", @@ -775,7 +894,7 @@ "baseUrl" : "/", "surrogateAuthRequired" : false, "enabled" : true, - "alwaysDisplayInConsole" : false, + "alwaysDisplayInConsole" : true, "clientAuthenticatorType" : "client-secret", "redirectUris" : [ "/Saml2/Acs" ], "webOrigins" : [ "https://localhost:*" ], @@ -793,15 +912,15 @@ "saml.assertion.signature" : "true", "saml.force.post.binding" : "false", "saml.encrypt" : "false", - "post.logout.redirect.uris" : "+", - "saml.server.signature" : "false", + "saml.server.signature" : "true", "saml.server.signature.keyinfo.ext" : "false", "saml.signing.certificate" : "MIIClzCCAX8CBgGMWViuFDANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARzYW1sMB4XDTIzMTIxMTE0NDUzM1oXDTMzMTIxMTE0NDcxM1owDzENMAsGA1UEAwwEc2FtbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJv58Hu1ASYA1K+nY1qwcc9C+oOyusVn416xNeJIA1ZDXHv7d3u2jsjtScY9o/G4P04H5pikbQed6aW/BHvrgGjR9qYqC8uXiN1d0PfyfCDkOW3+2eQbTK3buC0t8ty/WtIAHfn7o0yYEx/qcZ0KIZaHbwYETux9qwVyx7UJRga1Nxgh3JTUQP9WXOAHMJGXFNQTOsqiLcaN2c+fJ71g+Js1IrT/8HKhTGb2BgAmTiT3Ly1kMrPkUpZX8MCBK8T7srVJ7nAb5I5K2wFX8zJP3QNWi6aFdLNzYQmAV/fEUx8AeKWG+1zMsOc5gSMZhhJuMLxwy/D05ySg+QWZmUXSXS8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAOacJf764zEmGh2PKKIYye0Ah9qA0TnI1ocAZP/rmADsdv/tCOblodIR+TSnaLsNjyod4oAe431ydnp/ldyOZRNn63vJjL8NGyUwqgwH3JQdMl9/rMaMr1whQn4Y2pOEOe+ajTSW0ewUYi4vTJcQ0hZssTCll/4eVUtn20vgjaMnDCHaljxC7HmrfwTNmDgbto4+3Ku2oyoEEXUCGdANx86Iq7luPu+HzJrrtD0sjKIWlXFkjAwp2Fg4hue8AABPsrHTb4MfncFZrb3hpKOXyqKeGG4OZml4QYmWVENy0ZnMmja0nuGa+0hXKLYgmhrqX+r9Qz9Kq220/E6tVCUiU9w==", "saml.artifact.binding.identifier" : "KrXTZEZ4jv5lKJLhd8JD8LtnSMw=", "saml.artifact.binding" : "true", + "saml_single_logout_service_url_redirect" : "/Saml2/Logout", "saml.signature.algorithm" : "RSA_SHA256", "saml_force_name_id_format" : "false", - "saml.client.signature" : "false", + "saml.client.signature" : "true", "saml.authnstatement" : "true", "display.on.consent.screen" : "false", "saml_name_id_format" : "username", @@ -1653,7 +1772,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper" ] } }, { "id" : "a7dfdd72-6318-4754-849a-b2d4cbb240f8", @@ -1669,7 +1788,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper" ] } }, { "id" : "c040d26e-f82f-46d8-af31-fa51a695f323", @@ -2278,17 +2397,19 @@ "firstBrokerLoginFlow" : "first broker login", "attributes" : { "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaExpiresIn" : "120", "cibaAuthRequestedUserHint" : "login_hint", - "oauth2DeviceCodeLifespan" : "600", "clientOfflineSessionMaxLifespan" : "0", "oauth2DevicePollingInterval" : "5", "clientSessionIdleTimeout" : "0", - "parRequestUriLifespan" : "60", - "clientSessionMaxLifespan" : "0", "clientOfflineSessionIdleTimeout" : "0", "cibaInterval" : "5", - "realmReusableOtpCode" : "false" + "realmReusableOtpCode" : "false", + "cibaExpiresIn" : "120", + "oauth2DeviceCodeLifespan" : "600", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0", + "frontendUrl" : "", + "acr.loa.map" : "{}" }, "keycloakVersion" : "24.0.2", "userManagedAccessAllowed" : false, diff --git a/samples/AspNetCoreSample/Program.cs b/samples/AspNetCoreSample/Program.cs index 284343db..442e6886 100644 --- a/samples/AspNetCoreSample/Program.cs +++ b/samples/AspNetCoreSample/Program.cs @@ -165,13 +165,18 @@ await context.Options.Events.RedirectToLogout(new RedirectContext Date: Wed, 27 Mar 2024 00:20:24 +0800 Subject: [PATCH 2/2] Remove SAML signing certificate for OWIN sample --- samples/OwinSample/OwinSample.csproj | 3 --- samples/OwinSample/Startup.cs | 33 +++++++++++----------------- samples/OwinSample/appsettings.json | 6 +---- 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/samples/OwinSample/OwinSample.csproj b/samples/OwinSample/OwinSample.csproj index d7c294bc..93f4bff5 100644 --- a/samples/OwinSample/OwinSample.csproj +++ b/samples/OwinSample/OwinSample.csproj @@ -83,9 +83,6 @@ appsettings.json PreserveNewest - - PreserveNewest - diff --git a/samples/OwinSample/Startup.cs b/samples/OwinSample/Startup.cs index 2138806b..1d8dccac 100644 --- a/samples/OwinSample/Startup.cs +++ b/samples/OwinSample/Startup.cs @@ -1,7 +1,6 @@ using System; -using System.IO; +using System.Linq; using System.Security.Claims; -using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using System.Web; using System.Web.Helpers; @@ -225,24 +224,7 @@ public void Configuration(IAppBuilder app) private static Saml2AuthenticationOptions CreateSaml2Options(IConfiguration configuration) { - var spOptions = new SPOptions { EntityId = new EntityId(configuration["SAML2:SP:EntityId"]) }; - spOptions.ServiceCertificates.Add(new X509Certificate2( - HttpContext.Current.Server.MapPath(configuration["SAML2:SP:Certificate:Path"]), - configuration["SAML2:SP:Certificate:Pass"], - X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet)); - var decryptionCertificatePath = - HttpContext.Current.Server.MapPath(configuration["SAML2:SP:Decryption:Certificate:Path"]); - if (!string.IsNullOrWhiteSpace(decryptionCertificatePath) && File.Exists(decryptionCertificatePath)) - { - spOptions.ServiceCertificates.Add(new ServiceCertificate - { - Certificate = new X509Certificate2(decryptionCertificatePath, - configuration["SAML2:SP:Decryption:Certificate:Pass"]!, - X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet), - Use = CertificateUse.Encryption - }); - } - + var spOptions = new SPOptions { EntityId = new EntityId(configuration["SAML2:SP:EntityId"]), AuthenticateRequestSigningBehavior = SigningBehavior.Never }; spOptions.TokenValidationParametersTemplate.NameClaimType = ClaimTypes.NameIdentifier; var options = new Saml2AuthenticationOptions(false) { SPOptions = spOptions }; var idp = new IdentityProvider(new EntityId(configuration["SAML2:IdP:EntityId"]), spOptions) @@ -250,6 +232,17 @@ private static Saml2AuthenticationOptions CreateSaml2Options(IConfiguration conf MetadataLocation = configuration["SAML2:IdP:MetadataLocation"] }; options.IdentityProviders.Add(idp); + options.Notifications.MetadataCreated = (metadata, _) => + { + var ssoDescriptor = metadata.RoleDescriptors.OfType().First(); + ssoDescriptor.WantAssertionsSigned = true; + }; + // Avoid browsers downloading metadata as file + options.Notifications.MetadataCommandResultCreated = result => + { + result.ContentType = "application/xml"; + result.Headers.Remove("Content-Disposition"); + }; // https://github.com/aspnet/AspNetKatana/wiki/System.Web-response-cookie-integration-issues options.CookieManager = new SystemWebCookieManager(); return options; diff --git a/samples/OwinSample/appsettings.json b/samples/OwinSample/appsettings.json index 6b2482b6..d4885aab 100644 --- a/samples/OwinSample/appsettings.json +++ b/samples/OwinSample/appsettings.json @@ -14,11 +14,7 @@ "MetadataLocation": "https://auth.dev.local/realms/demo/protocol/saml/descriptor" }, "SP": { - "EntityId": "saml", - "Certificate": { - "Path": "~/App_Data/saml.p12", - "Pass": "changeit" - } + "EntityId": "https://localhost:44345/Saml2/" } } }