keycloak-aplcache

saml unit tests

10/20/2014 6:31:00 PM

Details

pom.xml 5(+5 -0)

diff --git a/pom.xml b/pom.xml
index 8b26ca0..623b0e0 100755
--- a/pom.xml
+++ b/pom.xml
@@ -238,6 +238,11 @@
             </dependency>
             <dependency>
                 <groupId>org.picketlink</groupId>
+                <artifactId>picketlink-wildlfy-common</artifactId>
+                <version>${picketlink.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.picketlink</groupId>
                 <artifactId>picketlink-idm-simple-schema</artifactId>
                 <version>${picketlink.version}</version>
             </dependency>
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index cb27bf9..aacc9a9 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -93,7 +93,7 @@ public class SamlService {
     public abstract class BindingProtocol {
         protected Response basicChecks(String samlRequest, String samlResponse) {
             if (!checkSsl()) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.SSL_REQUIRED);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
             }
@@ -104,7 +104,7 @@ public class SamlService {
             }
 
             if (samlRequest == null && samlResponse == null) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.INVALID_TOKEN);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
 
@@ -113,7 +113,7 @@ public class SamlService {
         }
 
         protected Response handleSamlResponse(String samleResponse, String relayState) {
-            event.event(EventType.LOGIN_ERROR);
+            event.event(EventType.LOGIN);
             event.error(Errors.INVALID_TOKEN);
             return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
         }
@@ -121,7 +121,7 @@ public class SamlService {
         protected Response handleSamlRequest(String samlRequest, String relayState) {
             SAMLDocumentHolder documentHolder = extractDocument(samlRequest);
             if (documentHolder == null) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.INVALID_TOKEN);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
             }
@@ -133,23 +133,23 @@ public class SamlService {
             ClientModel client = realm.findClient(issuer);
 
             if (client == null) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.CLIENT_NOT_FOUND);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown login requester.");
             }
 
             if (!client.isEnabled()) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.CLIENT_DISABLED);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Login requester not enabled.");
             }
             if ((client instanceof ApplicationModel) && ((ApplicationModel)client).isBearerOnly()) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.NOT_ALLOWED);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Bearer-only applications are not allowed to initiate browser login");
             }
             if (client.isDirectGrantsOnly()) {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.NOT_ALLOWED);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "direct-grants-only clients are not allowed to initiate browser login");
             }
@@ -158,7 +158,7 @@ public class SamlService {
                 verifySignature(documentHolder, client);
             } catch (VerificationException e) {
                 SamlService.logger.error("request validation failed", e);
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.INVALID_SIGNATURE);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid requester.");
             }
@@ -173,7 +173,7 @@ public class SamlService {
                 return logoutRequest(logout, client);
 
             } else {
-                event.event(EventType.LOGIN_ERROR);
+                event.event(EventType.LOGIN);
                 event.error(Errors.INVALID_TOKEN);
                 return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
             }
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 67068d8..b7b5428 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -208,6 +208,17 @@
             <groupId>org.picketbox</groupId>
             <artifactId>picketbox-ldap</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-wildlfy-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.wildfly</groupId>
+            <artifactId>wildfly-undertow</artifactId>
+            <version>${wildfly.version}</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
     <build>
         <plugins>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlKeycloakRule.java
new file mode 100755
index 0000000..ab06c66
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlKeycloakRule.java
@@ -0,0 +1,154 @@
+package org.keycloak.testsuite.saml;
+
+import io.undertow.security.idm.Account;
+import io.undertow.security.idm.Credential;
+import io.undertow.security.idm.IdentityManager;
+import io.undertow.server.handlers.resource.Resource;
+import io.undertow.server.handlers.resource.ResourceChangeListener;
+import io.undertow.server.handlers.resource.ResourceManager;
+import io.undertow.server.handlers.resource.URLResource;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.LoginConfig;
+import io.undertow.servlet.api.SecurityConstraint;
+import io.undertow.servlet.api.ServletInfo;
+import io.undertow.servlet.api.WebResourceCollection;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.picketlink.identity.federation.bindings.wildfly.sp.SPServletExtension;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.security.Principal;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class SamlKeycloakRule extends AbstractKeycloakRule {
+
+    public static class SendUsernameServlet extends HttpServlet {
+        @Override
+        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+            resp.setContentType("text/plain");
+            OutputStream stream = resp.getOutputStream();
+            Principal principal = req.getUserPrincipal();
+            String name = principal.getName();
+            stream.write(name.getBytes());
+        }
+        @Override
+        protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+            resp.setContentType("text/plain");
+            OutputStream stream = resp.getOutputStream();
+            Principal principal = req.getUserPrincipal();
+            if (principal == null) {
+                stream.write("null".getBytes());
+                return;
+            }
+            String name = principal.getName();
+            stream.write(name.getBytes());
+        }
+    }
+
+    public static class TestResourceManager implements ResourceManager {
+
+        private final String basePath;
+
+        public TestResourceManager(String basePath){
+            this.basePath = basePath;
+        }
+
+        @Override
+        public Resource getResource(String path) throws IOException {
+            String temp = path;
+            String fullPath = basePath + temp;
+            URL url = getClass().getResource(fullPath);
+            if (url == null) {
+                System.out.println("url is null: " + fullPath);
+            }
+            return new URLResource(url, url.openConnection(), path);
+        }
+
+        @Override
+        public boolean isResourceChangeListenerSupported() {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void registerResourceChangeListener(ResourceChangeListener listener) {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void removeResourceChangeListener(ResourceChangeListener listener) {
+            throw new RuntimeException();
+        }
+
+        @Override
+        public void close() throws IOException {
+            throw new RuntimeException();
+        }
+    }
+
+    public static class TestIdentityManager implements IdentityManager {
+        @Override
+        public Account verify(Account account) {
+            return account;
+        }
+
+        @Override
+        public Account verify(String userName, Credential credential) {
+            throw new RuntimeException("WTF");
+        }
+
+        @Override
+        public Account verify(Credential credential) {
+            throw new RuntimeException();
+        }
+    }
+
+    @Override
+    protected void setupKeycloak() {
+        String realmJson = getRealmJson();
+        server.importRealm(getClass().getResourceAsStream(realmJson));
+        initWars();
+    }
+
+    public abstract void initWars();
+
+    public void initializeSamlSecuredWar(String warResourcePath, String contextPath, String warDeploymentName, ClassLoader classLoader) {
+
+        ServletInfo regularServletInfo = new ServletInfo("servlet", SendUsernameServlet.class)
+                .addMapping("/*");
+
+        SecurityConstraint constraint = new SecurityConstraint();
+        WebResourceCollection collection = new WebResourceCollection();
+        collection.addUrlPattern("/*");
+        constraint.addWebResourceCollection(collection);
+        constraint.addRoleAllowed("manager");
+        LoginConfig loginConfig = new LoginConfig("FORM", "Test Realm");
+
+        ResourceManager resourceManager = new TestResourceManager(warResourcePath);
+
+        DeploymentInfo deploymentInfo = new DeploymentInfo()
+                .setClassLoader(classLoader)
+                .setIdentityManager(new TestIdentityManager())
+                .setContextPath(contextPath)
+                .setDeploymentName(warDeploymentName)
+                .setLoginConfig(loginConfig)
+                .setResourceManager(resourceManager)
+                .addServlets(regularServletInfo)
+                .addSecurityConstraint(constraint)
+                .addServletExtension(new SPServletExtension());
+        server.getServer().deploy(deploymentInfo);
+    }
+
+    public String getRealmJson() {
+        return "/saml/testsaml.json";
+    }
+
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlSignedPostBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlSignedPostBindingTest.java
new file mode 100755
index 0000000..87d5db7
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlSignedPostBindingTest.java
@@ -0,0 +1,80 @@
+package org.keycloak.testsuite.saml;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlSignedPostBindingTest {
+
+    @ClassRule
+    public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
+        @Override
+        public void initWars() {
+             ClassLoader classLoader = SamlSignedPostBindingTest.class.getClassLoader();
+
+            initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig",  "post-sig.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);
+
+        }
+
+        @Override
+        public String getRealmJson() {
+            return "/saml/testsaml.json";
+        }
+    };
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+    @WebResource
+    protected WebDriver driver;
+    @WebResource
+    protected LoginPage loginPage;
+
+    @Test
+    @Ignore
+    public void runit() throws Exception {
+        Thread.sleep(10000000);
+    }
+
+
+    @Test
+    public void testSignedLoginLogout() {
+        driver.navigate().to("http://localhost:8081/sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        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");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+
+    }
+    @Test
+    public void testBadClientSignature() {
+        driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        Assert.assertEquals(driver.getTitle(), "We're sorry...");
+
+    }
+
+    @Test
+    public void testBadRealmSignature() {
+        driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
+        loginPage.login("bburke", "password");
+        Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("null"));
+    }
+
+
+}
diff --git a/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/keystore.jks
new file mode 100755
index 0000000..6a3e3ba
Binary files /dev/null and b/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/picketlink.xml
new file mode 100755
index 0000000..6114ef1
--- /dev/null
+++ b/testsuite/integration/src/test/resources/saml/bad-client-signed-post/WEB-INF/picketlink.xml
@@ -0,0 +1,31 @@
+<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
+	<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
+		ServerEnvironment="tomcat" BindingType="POST" SupportsSignatures="true">
+		<IdentityURL>${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml}
+		</IdentityURL>
+		<ServiceURL>${sales-post-sig.url::http://localhost:8081/bad-client-sales-post-sig/}
+		</ServiceURL>
+		<KeyProvider
+			ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
+			<Auth Key="KeyStoreURL" Value="saml/bad-client-signed-post/WEB-INF/keystore.jks" />
+			<Auth Key="KeyStorePass" Value="store123" />
+			<Auth Key="SigningKeyPass" Value="test123" />
+			<Auth Key="SigningKeyAlias" Value="http://localhost:8081/bad-client-sales-post-sig/" />
+			<ValidatingAlias Key="localhost" Value="demo" />
+			<ValidatingAlias Key="127.0.0.1" Value="demo" />
+		</KeyProvider>
+
+	</PicketLinkSP>
+	<Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureValidationHandler" />
+	</Handlers>
+</PicketLink>
diff --git a/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/keystore.jks
new file mode 100755
index 0000000..215384c
Binary files /dev/null and b/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/picketlink.xml
new file mode 100755
index 0000000..6012916
--- /dev/null
+++ b/testsuite/integration/src/test/resources/saml/bad-realm-signed-post/WEB-INF/picketlink.xml
@@ -0,0 +1,31 @@
+<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
+	<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
+		ServerEnvironment="tomcat" BindingType="POST" SupportsSignatures="true">
+		<IdentityURL>${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml}
+		</IdentityURL>
+		<ServiceURL>${sales-post-sig.url::http://localhost:8081/bad-realm-sales-post-sig/}
+		</ServiceURL>
+		<KeyProvider
+			ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
+			<Auth Key="KeyStoreURL" Value="saml/bad-realm-signed-post/WEB-INF/keystore.jks" />
+			<Auth Key="KeyStorePass" Value="store123" />
+			<Auth Key="SigningKeyPass" Value="test123" />
+			<Auth Key="SigningKeyAlias" Value="http://localhost:8081/bad-realm-sales-post-sig/" />
+			<ValidatingAlias Key="localhost" Value="demo" />
+			<ValidatingAlias Key="127.0.0.1" Value="demo" />
+		</KeyProvider>
+
+	</PicketLinkSP>
+	<Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureValidationHandler" />
+	</Handlers>
+</PicketLink>
diff --git a/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/picketlink.xml b/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/picketlink.xml
new file mode 100755
index 0000000..39ea935
--- /dev/null
+++ b/testsuite/integration/src/test/resources/saml/signed-post/WEB-INF/picketlink.xml
@@ -0,0 +1,31 @@
+<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
+	<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
+		ServerEnvironment="tomcat" BindingType="POST" SupportsSignatures="true">
+		<IdentityURL>${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml}
+		</IdentityURL>
+		<ServiceURL>${sales-post-sig.url::http://localhost:8081/sales-post-sig/}
+		</ServiceURL>
+		<KeyProvider
+			ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
+			<Auth Key="KeyStoreURL" Value="saml/signed-post/WEB-INF/keystore.jks" />
+			<Auth Key="KeyStorePass" Value="store123" />
+			<Auth Key="SigningKeyPass" Value="test123" />
+			<Auth Key="SigningKeyAlias" Value="http://localhost:8080/sales-post-sig/" />
+			<ValidatingAlias Key="localhost" Value="demo" />
+			<ValidatingAlias Key="127.0.0.1" Value="demo" />
+		</KeyProvider>
+
+	</PicketLinkSP>
+	<Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureGenerationHandler" />
+		<Handler
+			class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureValidationHandler" />
+	</Handlers>
+</PicketLink>
diff --git a/testsuite/integration/src/test/resources/saml/testsaml.json b/testsuite/integration/src/test/resources/saml/testsaml.json
new file mode 100755
index 0000000..0bde9d4
--- /dev/null
+++ b/testsuite/integration/src/test/resources/saml/testsaml.json
@@ -0,0 +1,142 @@
+{
+    "id": "demo",
+    "realm": "demo",
+    "enabled": true,
+    "sslRequired": "external",
+    "registrationAllowed": true,
+    "resetPasswordAllowed": true,
+    "passwordCredentialGrantAllowed": true,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "user" ],
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "users" : [
+        {
+            "username" : "bburke",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": ["manager"]
+        }
+    ],
+    "applications": [
+        {
+            "name": "http://localhost:8081/sales-post/",
+            "enabled": true,
+            "fullScopeAllowed": true,
+            "protocol": "saml",
+            "baseUrl": "http://localhost:8081/sales-post",
+            "adminUrl": "http://localhost:8081/sales-post",
+            "redirectUris": [
+                "http://localhost:8081/sales-post/*"
+            ]
+        },
+        {
+            "name": "http://localhost:8081/sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-sig",
+            "adminUrl": "http://localhost:8081/sales-post-sig",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-sig/*"
+            ],
+            "attributes": {
+                "samlServerSignature": "true",
+                "samlClientSignature": "true",
+                "privateKey": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
+                "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB",
+                "X509Certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/bad-realm-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/bad-realm-sales-post-sig",
+            "adminUrl": "http://localhost:8081/bad-realm-sales-post-sig",
+            "redirectUris": [
+                "http://localhost:8081/bad-realm-sales-post-sig/*"
+            ],
+            "attributes": {
+                "samlServerSignature": "true",
+                "samlClientSignature": "true",
+                "privateKey": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
+                "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB",
+                "X509Certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/bad-client-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/bad-client-sales-post-sig",
+            "adminUrl": "http://localhost:8081/bad-client-sales-post-sig",
+            "redirectUris": [
+                "http://localhost:8081/bad-client-sales-post-sig/*"
+            ],
+            "attributes": {
+                "samlServerSignature": "true",
+                "samlClientSignature": "true",
+                "privateKey": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
+                "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB",
+                "X509Certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/sales-post-enc/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-enc",
+            "adminUrl": "http://localhost:8081/sales-post-enc",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-enc/*"
+            ],
+            "attributes": {
+                "samlServerSignature": "true",
+                "samlClientSignature": "true",
+                "samlEncrypt": "true",
+                "privateKey": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
+                "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB",
+                "X509Certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/employee-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/employee-sig",
+            "adminUrl": "http://localhost:8081/employee-sig",
+            "redirectUris": [
+                "http://localhost:8081/employee-sig/*"
+            ],
+            "attributes": {
+                "samlServerSignature": "true",
+                "samlClientSignature": "true",
+                "privateKey": "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",
+                "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQAB",
+                "X509Certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "manager",
+                "description": "Have Manager privileges"
+            }
+        ]
+    }
+}