Merge pull request #4351 from hmlnarik/KEYCLOAK-4446-Failed-to-process-response-when-reject-consent-with-turned-on-encryption
KEYCLOAK-4775 Added encryption certificate to SAML metadata
This commit is contained in:
commit
121ec2603b
7 changed files with 55 additions and 10 deletions
|
@ -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:
|
||||
|
|
|
@ -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" +
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue