diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java index faee3c8f8dd..82c2ebc7edf 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java @@ -22,6 +22,7 @@ public class ApplicationRepresentation { protected Integer notBefore; protected Boolean bearerOnly; protected Boolean publicClient; + protected Boolean frontchannelLogout; protected String protocol; protected Map attributes; protected Boolean fullScopeAllowed; @@ -179,4 +180,12 @@ public class ApplicationRepresentation { public void setRegisteredNodes(Map registeredNodes) { this.registeredNodes = registeredNodes; } + + public Boolean isFrontchannelLogout() { + return frontchannelLogout; + } + + public void setFrontchannelLogout(Boolean frontchannelLogout) { + this.frontchannelLogout = frontchannelLogout; + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java index e61cdfc5279..de65ae6c2ee 100755 --- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java @@ -21,6 +21,7 @@ public class OAuthClientRepresentation { protected Map attributes; protected Boolean directGrantsOnly; protected Boolean fullScopeAllowed; + protected Boolean frontchannelLogout; public String getId() { @@ -126,4 +127,12 @@ public class OAuthClientRepresentation { public void setAttributes(Map attributes) { this.attributes = attributes; } + + public Boolean isFrontchannelLogout() { + return frontchannelLogout; + } + + public void setFrontchannelLogout(Boolean frontchannelLogout) { + this.frontchannelLogout = frontchannelLogout; + } } diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index a96e217a474..42c44232754 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -230,6 +230,7 @@ public class ModelToRepresentation { rep.setEnabled(applicationModel.isEnabled()); rep.setAdminUrl(applicationModel.getManagementUrl()); rep.setPublicClient(applicationModel.isPublicClient()); + rep.setFrontchannelLogout(applicationModel.isFrontchannelLogout()); rep.setProtocol(applicationModel.getProtocol()); rep.setAttributes(applicationModel.getAttributes()); rep.setFullScopeAllowed(applicationModel.isFullScopeAllowed()); @@ -266,6 +267,7 @@ public class ModelToRepresentation { rep.setName(model.getClientId()); rep.setEnabled(model.isEnabled()); rep.setPublicClient(model.isPublicClient()); + rep.setFrontchannelLogout(model.isFrontchannelLogout()); rep.setProtocol(model.getProtocol()); rep.setAttributes(model.getAttributes()); rep.setFullScopeAllowed(model.isFullScopeAllowed()); diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index 2ab0afebfb5..23da5c5d00e 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -372,6 +372,7 @@ public class RepresentationToModel { applicationModel.setBaseUrl(resourceRep.getBaseUrl()); if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly()); if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient()); + if (resourceRep.isFrontchannelLogout() != null) applicationModel.setFrontchannelLogout(resourceRep.isFrontchannelLogout()); if (resourceRep.getProtocol() != null) applicationModel.setProtocol(resourceRep.getProtocol()); if (resourceRep.isFullScopeAllowed() != null) { applicationModel.setFullScopeAllowed(resourceRep.isFullScopeAllowed()); @@ -458,6 +459,7 @@ public class RepresentationToModel { if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly()); if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient()); if (rep.isFullScopeAllowed() != null) resource.setFullScopeAllowed(rep.isFullScopeAllowed()); + if (rep.isFrontchannelLogout() != null) resource.setFrontchannelLogout(rep.isFrontchannelLogout()); if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl()); if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl()); if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired()); @@ -579,6 +581,7 @@ public class RepresentationToModel { if (rep.getName() != null) model.setClientId(rep.getName()); if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled()); if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient()); + if (rep.isFrontchannelLogout() != null) model.setFrontchannelLogout(rep.isFrontchannelLogout()); if (rep.isFullScopeAllowed() != null) model.setFullScopeAllowed(rep.isFullScopeAllowed()); if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly()); if (rep.getClaims() != null) { diff --git a/pom.xml b/pom.xml index 8e645aa08b6..7ae9a0776e8 100755 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 3.0.9.Final 1.1.1.Final - 2.7.0.CR2 + 2.7.0.CR3 1.0.2.Final 2.11.3 3.1.4.GA diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java index 84cf7ee9e57..d17c72491b8 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java @@ -1,5 +1,6 @@ package org.keycloak.protocol.saml; +import org.jboss.logging.Logger; import org.picketlink.common.constants.GeneralConstants; import org.picketlink.common.constants.JBossSAMLConstants; import org.picketlink.common.constants.JBossSAMLURIConstants; @@ -38,6 +39,7 @@ import static org.picketlink.common.util.StringUtil.isNotNull; * @version $Revision: 1 $ */ public class SAML2BindingBuilder { + protected static final Logger logger = Logger.getLogger(SAML2BindingBuilder.class); protected KeyPair signingKeyPair; protected X509Certificate signingCertificate; @@ -148,6 +150,9 @@ public class SAML2BindingBuilder { public Response request() throws ConfigurationException, ProcessingException, IOException { return buildResponse(document, destination, true); } + public Response request(String actionUrl) throws ConfigurationException, ProcessingException, IOException { + return buildResponse(document, actionUrl, true); + } public Response response() throws ConfigurationException, ProcessingException, IOException { return buildResponse(document, destination, false); } @@ -186,13 +191,16 @@ public class SAML2BindingBuilder { return response(destination, false); } + public Response request(String redirect) throws ProcessingException, ConfigurationException, IOException { + return response(redirect, true); + } public Response request() throws ProcessingException, ConfigurationException, IOException { return response(destination, true); } private Response response(String redirectUri, boolean asRequest) throws ProcessingException, ConfigurationException, IOException { URI uri = responseUri(redirectUri, asRequest); - + if (logger.isDebugEnabled()) logger.trace("redirect-binding uri: " + uri.toString()); CacheControl cacheControl = new CacheControl(); cacheControl.setNoCache(true); return Response.status(302).location(uri) @@ -339,7 +347,9 @@ public class SAML2BindingBuilder { } protected String base64Encoded(Document document) throws ConfigurationException, ProcessingException, IOException { - byte[] responseBytes = org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil.getDocumentAsString(document).getBytes("UTF-8"); + String documentAsString = org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil.getDocumentAsString(document); + logger.debugv("saml docment: {0}", documentAsString); + byte[] responseBytes = documentAsString.getBytes("UTF-8"); return RedirectBindingUtil.deflateBase64URLEncode(responseBytes); } diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java index 65c902ceb6a..1d76e2f9330 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java @@ -53,6 +53,13 @@ public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder redirectClients = new LinkedList(); for (ClientSessionModel clientSession : userSession.getClientSessions()) { ClientModel client = clientSession.getClient(); + if (clientSession.getAction() == ClientSessionModel.Action.LOGGED_OUT) continue; if (client.isFrontchannelLogout()) { String authMethod = clientSession.getAuthMethod(); if (authMethod == null) continue; // must be a keycloak service like account redirectClients.add(clientSession); continue; } - if (client instanceof ApplicationModel && !client.isFrontchannelLogout() && clientSession.getAction() != ClientSessionModel.Action.LOGGED_OUT) { + if (client instanceof ApplicationModel && !client.isFrontchannelLogout()) { String authMethod = clientSession.getAuthMethod(); if (authMethod == null) continue; // must be a keycloak service like account LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod); protocol.setRealm(realm) .setUriInfo(uriInfo); try { + logger.debugv("backchannel logout to: {0}", client.getClientId()); protocol.backchannelLogout(userSession, clientSession); clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT); } catch (Exception e) { @@ -147,8 +149,12 @@ public class AuthenticationManager { // setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT); try { + logger.debugv("frontchannel logout to: {0}", nextRedirectClient.getClient().getClientId()); Response response = protocol.frontchannelLogout(userSession, nextRedirectClient); - if (response != null) return response; + if (response != null) { + logger.debug("returning frontchannel logout request to client"); + return response; + } } catch (Exception e) { logger.warn("Failed to logout client, continuing", e); } diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java index 55f4726d6de..25a3414b042 100755 --- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java +++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java @@ -328,7 +328,7 @@ public class ResourceAdminManager { return new GlobalRequestResult(); } - if (logger.isDebugEnabled()) logger.info("Sending push revocation to URLS: " + mgmtUrls); + if (logger.isDebugEnabled()) logger.debug("Sending push revocation to URLS: " + mgmtUrls); // Propagate this to all hosts GlobalRequestResult result = new GlobalRequestResult(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java index d63312010f9..b600305f533 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java @@ -54,6 +54,7 @@ public class SamlBindingTest { initializeSamlSecuredWar("/saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader); initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader); initializeSamlSecuredWar("/saml/signed-get", "/employee-sig", "employee-sig.war", classLoader); + initializeSamlSecuredWar("/saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader); initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader); initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader); initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader); @@ -79,9 +80,14 @@ public class SamlBindingTest { Thread.sleep(10000000); } - protected void checkLoggedOut() { - Assert.assertTrue(driver.getPageSource().contains("request-path: /logout.jsp")); - Assert.assertTrue(driver.getPageSource().contains("principal=null")); + protected void checkLoggedOut(String mainUrl) { + String pageSource = driver.getPageSource(); + System.out.println("*** logout pagesouce ***"); + System.out.println(pageSource); + System.out.println("driver url: " + driver.getCurrentUrl()); + Assert.assertTrue(pageSource.contains("request-path: /logout.jsp")); + driver.navigate().to(mainUrl); + Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); } @@ -94,7 +100,7 @@ public class SamlBindingTest { System.out.println(driver.getPageSource()); Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/sales-post?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post/"); } @Test public void testPostSignedLoginLogout() { @@ -104,7 +110,7 @@ public class SamlBindingTest { Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/"); Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post-sig/"); } @Test @@ -117,7 +123,7 @@ public class SamlBindingTest { Assert.assertFalse(driver.getPageSource().contains("bburke")); Assert.assertTrue(driver.getPageSource().contains("principal=G-")); driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post-sig-transient/"); } @Test @@ -130,7 +136,7 @@ public class SamlBindingTest { Assert.assertFalse(driver.getPageSource().contains("bburke")); Assert.assertTrue(driver.getPageSource().contains("principal=G-")); driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/"); } @Test @@ -142,7 +148,7 @@ public class SamlBindingTest { System.out.println(driver.getPageSource()); Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com")); driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post-sig-email/"); } @Test @@ -153,7 +159,45 @@ public class SamlBindingTest { Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/employee-sig/"); + + } + + @Test + public void testRedirectSignedLoginLogoutFrontNoSSO() { + driver.navigate().to("http://localhost:8081/employee-sig-front/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true"); + checkLoggedOut("http://localhost:8081/employee-sig-front/"); + + } + + @Test + public void testRedirectSignedLoginLogoutFront() { + // visit 1st app an logg in + System.out.println("visit 1st app "); + driver.navigate().to("http://localhost:8081/employee-sig/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); + System.out.println("login to form"); + loginPage.login("bburke", "password"); + Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + + // visit 2nd app + System.out.println("visit 2nd app "); + driver.navigate().to("http://localhost:8081/employee-sig-front/"); + Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); + Assert.assertTrue(driver.getPageSource().contains("bburke")); + + // logout of first app + System.out.println("GLO"); + driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); + checkLoggedOut("http://localhost:8081/employee-sig/"); + driver.navigate().to("http://localhost:8081/employee-sig-front/"); + Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); } @@ -165,7 +209,7 @@ public class SamlBindingTest { Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/"); Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-post-enc/"); } @Test @@ -213,7 +257,7 @@ public class SamlBindingTest { String pageSource = driver.getPageSource(); Assert.assertTrue(pageSource.contains("bburke")); driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true"); - checkLoggedOut(); + checkLoggedOut("http://localhost:8081/sales-metadata/"); } diff --git a/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/keystore.jks new file mode 100755 index 00000000000..4daad218a3f Binary files /dev/null and b/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/keystore.jks differ diff --git a/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/picketlink.xml new file mode 100755 index 00000000000..06fff8c498b --- /dev/null +++ b/testsuite/integration/src/test/resources/saml/signed-front-get/WEB-INF/picketlink.xml @@ -0,0 +1,38 @@ + + + ${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml} + + ${employee-sig.url::http://localhost:8081/employee-sig-front/} + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json index 4453c34fa07..0e31188b935 100755 --- a/testsuite/integration/src/test/resources/saml/testsaml.json +++ b/testsuite/integration/src/test/resources/saml/testsaml.json @@ -194,6 +194,26 @@ "saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5", "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp" } + }, + { + "name": "http://localhost:8081/employee-sig-front/", + "enabled": true, + "protocol": "saml", + "fullScopeAllowed": true, + "frontchannelLogout": true, + "baseUrl": "http://localhost:8081/employee-sig-front", + "adminUrl": "http://localhost:8081/employee-sig-front", + "redirectUris": [ + "http://localhost:8081/employee-sig-front/*" + ], + "attributes": { + "saml.server.signature": "true", + "saml.client.signature": "true", + "saml.signature.algorithm": "RSA_SHA1", + "saml.authnstatement": "true", + "saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5", + "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp" + } } ], "roles" : {