Details
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
old mode 100644
new mode 100755
index f38d840..bc007ae
--- a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java
@@ -18,6 +18,10 @@
package org.keycloak.broker.provider;
import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.RealmModel;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
/**
* @author Pedro Igor
@@ -35,6 +39,11 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel>
}
@Override
+ public Response export(UriInfo uriInfo, RealmModel realm, String format) {
+ return Response.noContent().build();
+ }
+
+ @Override
public void close() {
// no-op
}
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
old mode 100644
new mode 100755
index ac1e3dc..f754eeb
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java
@@ -19,9 +19,11 @@ package org.keycloak.broker.provider;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
/**
* @author Pedro Igor
@@ -76,4 +78,12 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
* @return
*/
Response retrieveToken(FederatedIdentityModel identity);
+
+ /**
+ * Export a representation of the IdentityProvider in a specific format. For example, a SAML EntityDescriptor
+ *
+ * @return
+ */
+ Response export(UriInfo uriInfo, RealmModel realm, String format);
+
}
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
old mode 100644
new mode 100755
index 1ad696c..c136c1d
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -24,6 +24,8 @@ import org.keycloak.broker.provider.AuthenticationResponse;
import org.keycloak.broker.provider.FederatedIdentity;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.RealmModel;
import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
import org.picketlink.common.constants.JBossSAMLConstants;
@@ -55,6 +57,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
@@ -85,7 +88,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
public AuthenticationResponse handleRequest(AuthenticationRequest request) {
try {
UriInfo uriInfo = request.getUriInfo();
- String issuerURL = UriBuilder.fromUri(uriInfo.getBaseUri()).build().toString();
+ RealmModel realm = request.getRealm();
+ String issuerURL = getEntityId(uriInfo, realm);
String destinationUrl = getConfig().getSingleSignOnServiceUrl();
String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
@@ -109,15 +113,15 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
.relayState(request.getState());
if (getConfig().isWantAuthnRequestsSigned()) {
- PrivateKey privateKey = request.getRealm().getPrivateKey();
- PublicKey publicKey = request.getRealm().getPublicKey();
+ PrivateKey privateKey = realm.getPrivateKey();
+ PublicKey publicKey = realm.getPublicKey();
if (privateKey == null) {
- throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + request.getRealm().getName() + "] does not have a private key.");
+ throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a private key.");
}
if (publicKey == null) {
- throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + request.getRealm().getName() + "] does not have a public key.");
+ throw new IdentityBrokerException("Identity Provider [" + getConfig().getName() + "] wants a signed authentication request. But the Realm [" + realm.getName() + "] does not have a public key.");
}
KeyPair keypair = new KeyPair(publicKey, privateKey);
@@ -136,6 +140,10 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
}
}
+ private String getEntityId(UriInfo uriInfo, RealmModel realm) {
+ return UriBuilder.fromUri(uriInfo.getBaseUri()).path("realms").path(realm.getName()).build().toString();
+ }
+
@Override
public String getRelayState(AuthenticationRequest request) {
return getRequestParameter(request, RELAY_STATE_PARAMETER);
@@ -283,4 +291,45 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
return requestParameters.getFirst(parameterName);
}
+
+ @Override
+ public Response export(UriInfo uriInfo, RealmModel realm, String format) {
+
+ String authnBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
+
+ if (getConfig().isPostBindingAuthnRequest()) {
+ authnBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
+ }
+
+ String assertionConsumerService = uriInfo.getBaseUriBuilder().path("realms").path(realm.getName()).path("broker").path(getConfig().getProviderId()).build().toString();
+
+
+
+ String descriptor =
+ "<EntityDescriptor 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" +
+// todo single logout service description
+// " <SingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8081/sales-metadata/\"/>\n" +
+ " <AssertionConsumerService\n" +
+ " Binding=\"" + authnBinding + "\" Location=\"" + assertionConsumerService + "\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";
+ return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index c95b618..0bf652b 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -167,6 +167,17 @@ public class IdentityBrokerService {
return getToken(providerId, false);
}
+ @GET
+ @Path("{provider_id}/export")
+ public Response export(@PathParam("provider_id") String providerId, @QueryParam("format") String format) {
+ try {
+ IdentityProvider identityProvider = getIdentityProvider(providerId);
+ return identityProvider.export(uriInfo, realmModel, format);
+ } catch (Exception e) {
+ return redirectToErrorPage("Could not export public broker configuration for identity provider [" + providerId + "].", e);
+ }
+ }
+
private Response getToken(String providerId, boolean forceRetrieval) {
this.event.event(EventType.IDENTITY_PROVIDER_RETRIEVE_TOKEN);
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 0198644..812696f 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -601,9 +601,6 @@ public class LoginActionsService {
return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection);
}
-
-
-
@Path("profile")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
index 60c0396..5757b28 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
@@ -8,7 +8,7 @@
"publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
"applications": [
{
- "name": "http://localhost:8081/auth/",
+ "name": "http://localhost:8081/auth/realms/realm-with-broker",
"enabled": true,
"redirectUris": [
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic"
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
index 4b3c505..db027d8 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
@@ -8,7 +8,7 @@
"publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",
"applications": [
{
- "name": "http://localhost:8081/auth/",
+ "name": "http://localhost:8081/auth/realms/realm-with-broker",
"enabled": true,
"redirectUris": [
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp"