keycloak-aplcache

Details

diff --git a/misc/Testsuite.md b/misc/Testsuite.md
index cb77ad7..7f5e036 100644
--- a/misc/Testsuite.md
+++ b/misc/Testsuite.md
@@ -29,6 +29,15 @@ When starting the server it can also import a realm from a json file:
 
     mvn exec:java -Pkeycloak-server -Dimport=testrealm.json
     
+When starting the server, https transport can be set up by setting keystore containing the server certificate
+and https port, optionally setting the truststore.
+
+    mvn exec:java -Pkeycloak-server \
+        -Djavax.net.ssl.trustStore=/path/to/truststore.jks \
+        -Djavax.net.ssl.keyStore=/path/to/keystore.jks \
+        -Djavax.net.ssl.keyStorePassword=CHANGEME \
+        -Dkeycloak.port.https=8443
+
 ### Live edit of html and styles
 
 The Keycloak test server can load resources directly from the filesystem instead of the classpath. This allows editing html, styles and updating images without restarting the server. To make the server use resources from the filesystem start with:
diff --git a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
index 5feda2b..b020eb7 100755
--- a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
+++ b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
@@ -23,14 +23,19 @@ package org.keycloak.saml;
  */
 public class SPMetadataDescriptor {
 
-    public static String getSPDescriptor(String binding, String assertionEndpoint, String logoutEndpoint, boolean wantAuthnRequestsSigned, boolean wantAssertionsSigned, String entityId, String nameIDPolicyFormat, String signingCerts) {
+    public static String getSPDescriptor(String binding, String assertionEndpoint, String logoutEndpoint,
+      boolean wantAuthnRequestsSigned, boolean wantAssertionsSigned, boolean wantAssertionsEncrypted,
+      String entityId, String nameIDPolicyFormat, String signingCerts, String encryptionCerts) {
         String descriptor =
                 "<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + entityId + "\">\n" +
                 "    <SPSSODescriptor AuthnRequestsSigned=\"" + wantAuthnRequestsSigned + "\" WantAssertionsSigned=\"" + wantAssertionsSigned + "\"\n" +
                 "            protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n";
-        if (wantAuthnRequestsSigned  && signingCerts != null) {
+        if (wantAuthnRequestsSigned && signingCerts != null) {
             descriptor += signingCerts;
         }
+        if (wantAssertionsEncrypted && encryptionCerts != null) {
+            descriptor += encryptionCerts;
+        }
         descriptor +=
                 "        <SingleLogoutService Binding=\"" + binding + "\" Location=\"" + logoutEndpoint + "\"/>\n" +
                 "        <NameIDFormat>" + nameIDPolicyFormat + "\n" +
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 886ee4d..6a4470b 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -54,6 +54,7 @@ import java.util.Set;
 import java.util.TreeSet;
 import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.keys.KeyMetadata;
+import org.keycloak.keys.KeyMetadata.Status;
 import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
 import org.keycloak.sessions.AuthenticationSessionModel;
 
@@ -237,18 +238,27 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
 
         boolean wantAuthnRequestsSigned = getConfig().isWantAuthnRequestsSigned();
         boolean wantAssertionsSigned = getConfig().isWantAssertionsSigned();
+        boolean wantAssertionsEncrypted = getConfig().isWantAssertionsEncrypted();
         String entityId = getEntityId(uriInfo, realm);
         String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
 
-        StringBuilder keysString = new StringBuilder();
+        StringBuilder signingKeysString = new StringBuilder();
+        StringBuilder encryptionKeysString = new StringBuilder();
         Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
           ? (int) (o2.getProviderPriority() - o1.getProviderPriority())
           : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
         keys.addAll(session.keys().getRsaKeys(realm, false));
         for (RsaKeyMetadata key : keys) {
-            addKeyInfo(keysString, key, KeyTypes.SIGNING.value());
+            addKeyInfo(signingKeysString, key, KeyTypes.SIGNING.value());
+
+            if (key.getStatus() == Status.ACTIVE) {
+                addKeyInfo(encryptionKeysString, key, KeyTypes.ENCRYPTION.value());
+            }
         }
-        String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint, wantAuthnRequestsSigned, wantAssertionsSigned, entityId, nameIDPolicyFormat, keysString.toString());
+        String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint,
+          wantAuthnRequestsSigned, wantAssertionsSigned, wantAssertionsEncrypted,
+          entityId, nameIDPolicyFormat, signingKeysString.toString(), encryptionKeysString.toString());
+
         return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
index b9c07ec..2261d52 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
@@ -127,7 +127,7 @@ public class SamlIDPDescriptorClientInstallation implements ClientInstallationPr
 
     @Override
     public String getHelpText() {
-        return "SAML Metadata IDSSODescriptor tailored for the client.  This is special because not every client may require things like digital signatures";
+        return "SAML Metadata IDPSSODescriptor tailored for the client.  This is special because not every client may require things like digital signatures";
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
index bd109e6..8a39de0 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
@@ -47,8 +47,10 @@ public class SamlSPDescriptorClientInstallation implements ClientInstallationPro
         String nameIdFormat = samlClient.getNameIDFormat();
         if (nameIdFormat == null) nameIdFormat = SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT;
         String spCertificate = SPMetadataDescriptor.xmlKeyInfo("        ", null, samlClient.getClientSigningCertificate(), KeyTypes.SIGNING.value(), true);
+        String encCertificate = SPMetadataDescriptor.xmlKeyInfo("        ", null, samlClient.getClientEncryptingCertificate(), KeyTypes.ENCRYPTION.value(), true);
         return SPMetadataDescriptor.getSPDescriptor(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get(), assertionUrl, logoutUrl,
-                samlClient.requiresClientSignature(), samlClient.requiresAssertionSignature(), client.getClientId(), nameIdFormat, spCertificate);
+                samlClient.requiresClientSignature(), samlClient.requiresAssertionSignature(), samlClient.requiresEncryption(),
+                client.getClientId(), nameIdFormat, spCertificate, encCertificate);
     }
 
     @Override
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
index d31dd10..f981377 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
@@ -39,7 +39,6 @@ import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.KeycloakApplication;
 import org.keycloak.testsuite.util.cli.TestsuiteCLI;
 import org.keycloak.util.JsonSerialization;
-import org.mvel2.util.Make;
 
 import javax.servlet.DispatcherType;
 import java.io.File;
@@ -51,6 +50,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import javax.net.ssl.SSLContext;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -64,6 +64,7 @@ public class KeycloakServer {
     public static class KeycloakServerConfig {
         private String host = "localhost";
         private int port = 8081;
+        private int portHttps = -1;
         private int workerThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2) * 8;
         private String resourcesHome;
 
@@ -75,6 +76,10 @@ public class KeycloakServer {
             return port;
         }
 
+        public int getPortHttps() {
+            return portHttps;
+        }
+
         public String getResourcesHome() {
             return resourcesHome;
         }
@@ -87,6 +92,10 @@ public class KeycloakServer {
             this.port = port;
         }
 
+        public void setPortHttps(int portHttps) {
+            this.portHttps = portHttps;
+        }
+
         public void setResourcesHome(String resourcesHome) {
             this.resourcesHome = resourcesHome;
         }
@@ -140,6 +149,10 @@ public class KeycloakServer {
             config.setPort(Integer.valueOf(System.getProperty("keycloak.port")));
         }
 
+        if (System.getProperty("keycloak.port.https") != null) {
+            config.setPortHttps(Integer.valueOf(System.getProperty("keycloak.port.https")));
+        }
+
         if (System.getProperty("keycloak.bind.address") != null) {
             config.setHost(System.getProperty("keycloak.bind.address"));
         }
@@ -312,6 +325,10 @@ public class KeycloakServer {
                 .setWorkerThreads(config.getWorkerThreads())
                 .setIoThreads(config.getWorkerThreads() / 8);
 
+        if (config.getPortHttps() != -1) {
+            builder = builder.addHttpsListener(config.getPortHttps(), config.getHost(), SSLContext.getDefault());
+        }
+
         server = new UndertowJaxrsServer();
         try {
             server.start(builder);
@@ -350,7 +367,9 @@ public class KeycloakServer {
                 info("Loading resources from " + config.getResourcesHome());
             }
 
-            info("Started Keycloak (http://" + config.getHost() + ":" + config.getPort() + "/auth) in "
+            info("Started Keycloak (http://" + config.getHost() + ":" + config.getPort() + "/auth"
+                    + (config.getPortHttps() > 0 ? ", https://" + config.getHost() + ":" + config.getPortHttps()+ "/auth" : "")
+                    + ") in "
                     + (System.currentTimeMillis() - start) + " ms\n");
         } catch (RuntimeException e) {
             server.stop();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
index 6833b34..de905bf 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
@@ -78,7 +78,7 @@ public class ValidationTest {
     public void testBrokerExportDescriptor() throws Exception {
         URL schemaFile = getClass().getResource("/schema/saml/v2/saml-schema-metadata-2.0.xsd");
         Source xmlFile = new StreamSource(new ByteArrayInputStream(SPMetadataDescriptor.getSPDescriptor(
-                "POST", "http://realm/assertion", "http://realm/logout", true, false, "test", SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT, KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate()
+                "POST", "http://realm/assertion", "http://realm/logout", true, false, false, "test", SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT, KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate(), ""
         ).getBytes()), "SP Descriptor");
         SchemaFactory schemaFactory = SchemaFactory
                 .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);