keycloak-developers
Changes
forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js 30(+22 -8)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-installation.html 2(+1 -1)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/ModAuthMellonClientInstallation.java 117(+117 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java 120(+120 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java 93(+93 -0)
Details
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 0014470..12b0428 100755
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -38,6 +38,7 @@ import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
import org.keycloak.saml.SAML2AuthnRequestBuilder;
import org.keycloak.saml.SAML2LogoutRequestBuilder;
import org.keycloak.saml.SAML2NameIDPolicyBuilder;
+import org.keycloak.saml.SPMetadataDescriptor;
import org.keycloak.saml.SignatureAlgorithm;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
@@ -227,31 +228,11 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
.build().toString();
-
- String descriptor =
- "<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + getEntityId(uriInfo, realm) + "\">\n" +
- " <SPSSODescriptor AuthnRequestsSigned=\"" + getConfig().isWantAuthnRequestsSigned() + "\"\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" +
- " <NameIDFormat>" + getConfig().getNameIDPolicyFormat() + "\n" +
- " </NameIDFormat>\n" +
- " <SingleLogoutService Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"/>\n" +
- " <AssertionConsumerService\n" +
- " Binding=\"" + authnBinding + "\" Location=\"" + endpoint + "\"\n" +
- " index=\"1\" isDefault=\"true\" />\n";
- if (getConfig().isWantAuthnRequestsSigned()) {
- descriptor +=
- " <KeyDescriptor use=\"signing\">\n" +
- " <dsig:KeyInfo xmlns:dsig=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
- " <dsig:X509Data>\n" +
- " <dsig:X509Certificate>\n" + realm.getCertificatePem() + "\n" +
- " </dsig:X509Certificate>\n" +
- " </dsig:X509Data>\n" +
- " </dsig:KeyInfo>\n" +
- " </KeyDescriptor>\n";
- }
- descriptor +=
- " </SPSSODescriptor>\n" +
- "</EntityDescriptor>\n";
+ boolean wantAuthnRequestsSigned = getConfig().isWantAuthnRequestsSigned();
+ String entityId = getEntityId(uriInfo, realm);
+ String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
+ String certificatePem = realm.getCertificatePem();
+ String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint, wantAuthnRequestsSigned, entityId, nameIDPolicyFormat, certificatePem);
return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index b0853cb..aac6a55 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -700,14 +700,28 @@ module.controller('ClientInstallationCtrl', function($scope, realm, client, serv
$scope.changeFormat = function() {
var url = ClientInstallation.url({ realm: $routeParams.realm, client: $routeParams.client, provider: $scope.configFormat.id });
- $http.get(url).success(function(data) {
- var installation = data;
- if ($scope.configFormat.mediaType == 'application/json') {
- installation = angular.fromJson(data);
- installation = angular.toJson(installation, true);
- }
- $scope.installation = installation;
- })
+ if ($scope.configFormat.mediaType == 'application/zip') {
+ $http({
+ url: url,
+ method: 'GET',
+ responseType: 'arraybuffer',
+ cache: false
+ }).success(function(data) {
+ var installation = data;
+ $scope.installation = installation;
+ }
+ );
+ } else {
+ $http.get(url).success(function (data) {
+ var installation = data;
+ if ($scope.configFormat.mediaType == 'application/json') {
+ installation = angular.fromJson(data);
+ installation = angular.toJson(installation, true);
+ }
+ $scope.installation = installation;
+ });
+ }
+
};
$scope.download = function() {
saveAs(new Blob([$scope.installation], { type: $scope.configFormat.mediaType }), $scope.configFormat.filename);
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-installation.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-installation.html
index 1530ba8..d03fdd2 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-installation.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-installation.html
@@ -26,7 +26,7 @@
<div class="form-group" ng-show="installation">
<div class="col-sm-12">
<a class="btn btn-primary btn-lg" data-ng-click="download()" type="submit" ng-show="installation">{{:: 'download' | translate}}</a>
- <textarea class="form-control" rows="20" kc-select-action="click">{{installation}}</textarea>
+ <textarea class="form-control" rows="20" kc-select-action="click" data-ng-hide="configFormat.downloadOnly">{{installation}}</textarea>
</div>
</div>
</fieldset>
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java b/saml/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
new file mode 100755
index 0000000..78ff2f3
--- /dev/null
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
@@ -0,0 +1,35 @@
+package org.keycloak.saml;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SPMetadataDescriptor {
+ public static String getSPDescriptor(String binding, String assertionEndpoint, String logoutEndpoint, boolean wantAuthnRequestsSigned, String entityId, String nameIDPolicyFormat, String certificatePem) {
+ String descriptor =
+ "<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + entityId + "\">\n" +
+ " <SPSSODescriptor AuthnRequestsSigned=\"" + wantAuthnRequestsSigned + "\"\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" +
+ " <NameIDFormat>" + nameIDPolicyFormat + "\n" +
+ " </NameIDFormat>\n" +
+ " <SingleLogoutService Binding=\"" + binding + "\" Location=\"" + logoutEndpoint + "\"/>\n" +
+ " <AssertionConsumerService\n" +
+ " Binding=\"" + binding + "\" Location=\"" + assertionEndpoint + "\"\n" +
+ " index=\"1\" isDefault=\"true\" />\n";
+ if (wantAuthnRequestsSigned) {
+ descriptor +=
+ " <KeyDescriptor use=\"signing\">\n" +
+ " <dsig:KeyInfo xmlns:dsig=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
+ " <dsig:X509Data>\n" +
+ " <dsig:X509Certificate>\n" + certificatePem + "\n" +
+ " </dsig:X509Certificate>\n" +
+ " </dsig:X509Data>\n" +
+ " </dsig:KeyInfo>\n" +
+ " </KeyDescriptor>\n";
+ }
+ descriptor +=
+ " </SPSSODescriptor>\n" +
+ "</EntityDescriptor>\n";
+ return descriptor;
+ }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/ModAuthMellonClientInstallation.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/ModAuthMellonClientInstallation.java
new file mode 100755
index 0000000..c7bd844
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/ModAuthMellonClientInstallation.java
@@ -0,0 +1,117 @@
+package org.keycloak.protocol.saml.installation;
+
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.ClientInstallationProvider;
+import org.keycloak.protocol.saml.SamlClient;
+import org.keycloak.protocol.saml.SamlProtocol;
+
+import javax.ws.rs.core.Response;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ModAuthMellonClientInstallation implements ClientInstallationProvider {
+ @Override
+ public Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI serverBaseUri) {
+ SamlClient samlClient = new SamlClient(client);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(baos);
+ String idpDescriptor = SamlIDPDescriptorClientInstallation.getIDPDescriptorForClient(realm, client, serverBaseUri);
+ String spDescriptor = SamlSPDescriptorClientInstallation.getSPDescriptorForClient(client);
+ String clientDirName = client.getClientId()
+ .replace('/', '_')
+ .replace(' ', '_');
+ try {
+ zip.putNextEntry(new ZipEntry(clientDirName + "/idp-metadata.xml"));
+ zip.write(idpDescriptor.getBytes());
+ zip.closeEntry();
+ zip.putNextEntry(new ZipEntry(clientDirName + "/sp-metadata.xml"));
+ zip.write(spDescriptor.getBytes());
+ zip.closeEntry();
+ if (samlClient.requiresClientSignature()) {
+ if (samlClient.getClientSigningPrivateKey() != null) {
+ zip.putNextEntry(new ZipEntry(clientDirName + "/client-private-key.pem"));
+ zip.write(samlClient.getClientSigningPrivateKey().getBytes());
+ zip.closeEntry();
+ }
+ if (samlClient.getClientSigningCertificate() != null) {
+ zip.putNextEntry(new ZipEntry(clientDirName + "/client-cert.pem"));
+ zip.write(samlClient.getClientSigningCertificate().getBytes());
+ zip.closeEntry();
+ }
+ }
+ zip.close();
+ baos.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+
+ return Response.ok(baos.toByteArray(), getMediaType()).build();
+ }
+
+ @Override
+ public String getProtocol() {
+ return SamlProtocol.LOGIN_PROTOCOL;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Mod Auth Mellon files";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "This is a zip file. It contains a SAML SP descriptor, SAML IDP descriptor, private key pem, and certificate pem that you will use to configure mod_auth_mellon for Apache. You'll use these files when crafting the main Apache configuration file. See mod_auth_mellon website for more details.";
+ }
+
+ @Override
+ public String getFilename() {
+ return "keycloak-mod-auth-mellon-sp-config.zip";
+ }
+
+ @Override
+ public String getMediaType() {
+ return "application/zip";
+ }
+
+ @Override
+ public boolean isDownloadOnly() {
+ return true;
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public ClientInstallationProvider create(KeycloakSession session) {
+ return this;
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public String getId() {
+ return "mod-auth-mellon";
+ }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
new file mode 100755
index 0000000..0caee9b
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
@@ -0,0 +1,120 @@
+package org.keycloak.protocol.saml.installation;
+
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.ClientInstallationProvider;
+import org.keycloak.protocol.saml.SamlClient;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.services.resources.RealmsResource;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.net.URI;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlIDPDescriptorClientInstallation implements ClientInstallationProvider {
+ public static String getIDPDescriptorForClient(RealmModel realm, ClientModel client, URI serverBaseUri) {
+ SamlClient samlClient = new SamlClient(client);
+ String idpEntityId = RealmsResource.realmBaseUrl(UriBuilder.fromUri(serverBaseUri)).build(realm.getName()).toString();
+ String idp = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<EntityDescriptor entityID=\"" + idpEntityId + "\"\n" +
+ " xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n" +
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
+ " <IDPSSODescriptor WantAuthnRequestsSigned=\"" + Boolean.toString(samlClient.requiresClientSignature()) + "\"\n" +
+ " protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n";
+ if (samlClient.forceNameIDFormat() && samlClient.getNameIDFormat() != null) {
+ idp += " " + samlClient.getNameIDFormat();
+ } else {
+ idp += " <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>\n" +
+ " <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n" +
+ " <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>\n" +
+ " <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>\n";
+ }
+ String bindUrl = RealmsResource.protocolUrl(UriBuilder.fromUri(serverBaseUri)).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString();
+ idp += "\n" +
+ " <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n" +
+ " Location=\"" + bindUrl + "\" />\n" +
+ " <SingleLogoutService\n" +
+ " Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n" +
+ " Location=\"" + bindUrl + "\" />\n" +
+ " <KeyDescriptor use=\"signing\">\n" +
+ " <dsig:KeyInfo xmlns:dsig=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
+ " <dsig:X509Data>\n" +
+ " <dsig:X509Certificate>\n" +
+ " " + realm.getCertificatePem() + "\n" +
+ " </dsig:X509Certificate>\n" +
+ " </dsig:X509Data>\n" +
+ " </dsig:KeyInfo>\n" +
+ " </KeyDescriptor>\n" +
+ " </IDPSSODescriptor>\n" +
+ "</EntityDescriptor>\n";
+ return idp;
+ }
+
+ @Override
+ public Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI serverBaseUri) {
+ String descriptor = getIDPDescriptorForClient(realm, client, serverBaseUri);
+ return Response.ok(descriptor, MediaType.TEXT_PLAIN_TYPE).build();
+ }
+
+ @Override
+ public String getProtocol() {
+ return SamlProtocol.LOGIN_PROTOCOL;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "SAML Metadata IDPSSODescriptor";
+ }
+
+ @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";
+ }
+
+ @Override
+ public String getFilename() {
+ return "client-tailored-saml-idp-metadata.xml";
+ }
+
+ public String getMediaType() {
+ return MediaType.APPLICATION_XML;
+ }
+
+ @Override
+ public boolean isDownloadOnly() {
+ return false;
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public ClientInstallationProvider create(KeycloakSession session) {
+ return this;
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public String getId() {
+ return "saml-idp-descriptor";
+ }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
new file mode 100755
index 0000000..0165e30
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
@@ -0,0 +1,93 @@
+package org.keycloak.protocol.saml.installation;
+
+import org.keycloak.Config;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.ClientInstallationProvider;
+import org.keycloak.protocol.saml.SamlClient;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.saml.SPMetadataDescriptor;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SamlSPDescriptorClientInstallation implements ClientInstallationProvider {
+ public static String getSPDescriptorForClient(ClientModel client) {
+ SamlClient samlClient = new SamlClient(client);
+ String assertionUrl = client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE);
+ if (assertionUrl == null) assertionUrl = client.getManagementUrl();
+ String logoutUrl = client.getAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE);
+ if (logoutUrl == null) logoutUrl = client.getManagementUrl();
+ String nameIdFormat = samlClient.getNameIDFormat();
+ if (nameIdFormat == null) nameIdFormat = SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT;
+ return SPMetadataDescriptor.getSPDescriptor(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get(), assertionUrl, logoutUrl, samlClient.requiresClientSignature(), client.getClientId(), nameIdFormat, samlClient.getClientSigningCertificate());
+ }
+
+ @Override
+ public Response generateInstallation(KeycloakSession session, RealmModel realm, ClientModel client, URI serverBaseUri) {
+ String descriptor = getSPDescriptorForClient(client);
+ return Response.ok(descriptor, MediaType.TEXT_PLAIN_TYPE).build();
+ }
+
+ @Override
+ public String getProtocol() {
+ return SamlProtocol.LOGIN_PROTOCOL;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "SAML Metadata SPSSODescriptor";
+ }
+
+ @Override
+ public String getHelpText() {
+ return "SAML SP Metadata EntityDescriptor or rather SPSSODescriptor. This is an XML file.";
+ }
+
+ @Override
+ public String getFilename() {
+ return "saml-sp-metadata.xml";
+ }
+
+ public String getMediaType() {
+ return MediaType.APPLICATION_XML;
+ }
+
+ @Override
+ public boolean isDownloadOnly() {
+ return false;
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public ClientInstallationProvider create(KeycloakSession session) {
+ return this;
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+
+ }
+
+ @Override
+ public String getId() {
+ return "saml-sp-descriptor";
+ }
+}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
index 3ac9892..3ddd883 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlClient.java
@@ -3,6 +3,8 @@ package org.keycloak.protocol.saml;
import org.keycloak.models.ClientConfigResolver;
import org.keycloak.models.ClientModel;
import org.keycloak.saml.SignatureAlgorithm;
+import org.keycloak.saml.common.constants.GeneralConstants;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -37,7 +39,24 @@ public class SamlClient extends ClientConfigResolver {
}
public String getNameIDFormat() {
- return resolveAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE);
+ String nameIdFormat = null;
+
+ String configuredNameIdFormat = resolveAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE);
+ if (configuredNameIdFormat != null) {
+ if (configuredNameIdFormat.equals("email")) {
+ nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get();
+ } else if (configuredNameIdFormat.equals("persistent")) {
+ nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
+ } else if (configuredNameIdFormat.equals("transient")) {
+ nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get();
+ } else if (configuredNameIdFormat.equals("username")) {
+ nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
+ } else {
+ nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
+ }
+ }
+ return nameIdFormat;
+
}
public void setNameIDFormat(String format) {
client.setAttribute(SamlConfigAttributes.SAML_NAME_ID_FORMAT_ATTRIBUTE, format);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index c76c853..d6af4d8 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -251,18 +251,8 @@ public class SamlProtocol implements LoginProtocol {
boolean forceFormat = samlClient.forceNameIDFormat();
String configuredNameIdFormat = samlClient.getNameIDFormat();
if ((nameIdFormat == null || forceFormat) && configuredNameIdFormat != null) {
- if (configuredNameIdFormat.equals("email")) {
- nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get();
- } else if (configuredNameIdFormat.equals("persistent")) {
- nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
- } else if (configuredNameIdFormat.equals("transient")) {
- nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get();
- } else if (configuredNameIdFormat.equals("username")) {
- nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
- } else {
- nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
- }
- }
+ nameIdFormat = configuredNameIdFormat;
+ }
if (nameIdFormat == null)
return SAML_DEFAULT_NAMEID_FORMAT;
return nameIdFormat;
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 bd6e846..1f90735 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
@@ -1,5 +1,6 @@
package org.keycloak.protocol.saml;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.PublicKey;
@@ -14,6 +15,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
@@ -477,7 +479,12 @@ public class SamlService extends AuthorizationEndpointBase {
@Path("descriptor")
@Produces(MediaType.APPLICATION_XML)
public String getDescriptor() throws Exception {
- InputStream is = getClass().getResourceAsStream("/idp-metadata-template.xml");
+ return getIDPMetadataDescriptor(uriInfo, realm);
+
+ }
+
+ public static String getIDPMetadataDescriptor(UriInfo uriInfo, RealmModel realm) throws IOException {
+ InputStream is = SamlService.class.getResourceAsStream("/idp-metadata-template.xml");
String template = StreamUtil.readString(is);
template = template.replace("${idp.entityID}", RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString());
template = template.replace("${idp.sso.HTTP-POST}", RealmsResource.protocolUrl(uriInfo).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString());
@@ -485,7 +492,6 @@ public class SamlService extends AuthorizationEndpointBase {
template = template.replace("${idp.sls.HTTP-POST}", RealmsResource.protocolUrl(uriInfo).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString());
template = template.replace("${idp.signing.certificate}", realm.getCertificatePem());
return template;
-
}
@GET
diff --git a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ClientInstallationProvider b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ClientInstallationProvider
index f8e9df5..f1d1ef2 100755
--- a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ClientInstallationProvider
+++ b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ClientInstallationProvider
@@ -1 +1,4 @@
org.keycloak.protocol.saml.installation.KeycloakSamlClientInstallation
+org.keycloak.protocol.saml.installation.SamlSPDescriptorClientInstallation
+org.keycloak.protocol.saml.installation.SamlIDPDescriptorClientInstallation
+org.keycloak.protocol.saml.installation.ModAuthMellonClientInstallation
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index e0ea200..7e13bf9 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -46,7 +46,12 @@ public class RealmsResource {
protected BruteForceProtector protector;
public static UriBuilder realmBaseUrl(UriInfo uriInfo) {
- return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getRealmResource");
+ UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
+ return realmBaseUrl(baseUriBuilder);
+ }
+
+ public static UriBuilder realmBaseUrl(UriBuilder baseUriBuilder) {
+ return baseUriBuilder.path(RealmsResource.class).path(RealmsResource.class, "getRealmResource");
}
public static UriBuilder accountUrl(UriBuilder base) {