Skip to content

Commit

Permalink
Merge pull request #566 from akunzai/saml-artifact-binding
Browse files Browse the repository at this point in the history
Fix SAML single logout not working
  • Loading branch information
akunzai authored Mar 26, 2024
2 parents 4e3b3b0 + 0cc03d4 commit 4659877
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 47 deletions.
143 changes: 132 additions & 11 deletions .devcontainer/keycloak/import/demo-realm.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"id" : "d6d2a42d-e33a-493d-b150-fb09e7d48d0d",
"realm" : "demo",
"displayName" : "DEMO",
"displayNameHtml" : "",
"notBefore" : 0,
"defaultSignatureAlgorithm" : "RS256",
"revokeRefreshToken" : false,
Expand Down Expand Up @@ -246,6 +248,7 @@
"attributes" : { }
} ],
"cas" : [ ],
"https://localhost:44345/Saml2/" : [ ],
"security-admin-console" : [ ],
"admin-cli" : [ ],
"account-console" : [ ],
Expand Down Expand Up @@ -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/",
Expand All @@ -775,7 +894,7 @@
"baseUrl" : "/",
"surrogateAuthRequired" : false,
"enabled" : true,
"alwaysDisplayInConsole" : false,
"alwaysDisplayInConsole" : true,
"clientAuthenticatorType" : "client-secret",
"redirectUris" : [ "/Saml2/Acs" ],
"webOrigins" : [ "https://localhost:*" ],
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 12 additions & 7 deletions samples/AspNetCoreSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,18 @@ await context.Options.Events.RedirectToLogout(new RedirectContext<CookieAuthenti
{
options.SPOptions.EntityId = new EntityId(builder.Configuration["SAML2:SP:EntityId"]);
options.SPOptions.AuthenticateRequestSigningBehavior = SigningBehavior.Never;
var spSigningCertPath = builder.Configuration["SAML2:SP:SigningCertificate:Path"];
if (!string.IsNullOrWhiteSpace(spSigningCertPath) && File.Exists(spSigningCertPath))
var signingCertPath = builder.Configuration["SAML2:SP:SigningCertificate:Path"];
if (!string.IsNullOrWhiteSpace(signingCertPath) && File.Exists(signingCertPath))
{
options.SPOptions.ServiceCertificates.Add(new X509Certificate2(
spSigningCertPath,
builder.Configuration["SAML2:SP:Certificate:Pass"],
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet));
// required for single logout
options.SPOptions.ServiceCertificates.Add(new ServiceCertificate
{
Use = CertificateUse.Signing,
Certificate = new X509Certificate2(
signingCertPath,
builder.Configuration["SAML2:SP:SigningCertificate:Pass"],
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet)
});
options.SPOptions.AuthenticateRequestSigningBehavior = SigningBehavior.IfIdpWantAuthnRequestsSigned;
}

Expand Down Expand Up @@ -217,4 +222,4 @@ await context.Options.Events.RedirectToLogout(new RedirectContext<CookieAuthenti

app.MapRazorPages();

app.Run();
app.Run();
6 changes: 5 additions & 1 deletion samples/AspNetCoreSample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
"MetadataLocation": "https://auth.dev.local/realms/demo/protocol/saml/descriptor"
},
"SP": {
"EntityId": "https://localhost:5001/Saml2/"
"EntityId": "https://localhost:5001/Saml2/",
"SigningCertificate": {
"Path": "saml.p12",
"Pass": "changeit"
}
}
}
}
File renamed without changes.
3 changes: 0 additions & 3 deletions samples/OwinSample/OwinSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@
<DependentUpon>appsettings.json</DependentUpon>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="App_Data\*.p12">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.Mvc" />
Expand Down
33 changes: 13 additions & 20 deletions samples/OwinSample/Startup.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -225,31 +224,25 @@ 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)
{
MetadataLocation = configuration["SAML2:IdP:MetadataLocation"]
};
options.IdentityProviders.Add(idp);
options.Notifications.MetadataCreated = (metadata, _) =>
{
var ssoDescriptor = metadata.RoleDescriptors.OfType<SpSsoDescriptor>().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;
Expand Down
6 changes: 1 addition & 5 deletions samples/OwinSample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
}
}
}

0 comments on commit 4659877

Please sign in to comment.