KEYCLOAK-2869 IdentityProvidersResource/IdentityProviderResource
This commit is contained in:
parent
49dc5363bb
commit
f337085ed0
4 changed files with 510 additions and 20 deletions
|
@ -17,19 +17,23 @@
|
||||||
|
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pedroigor
|
* @author pedroigor
|
||||||
|
@ -49,6 +53,34 @@ public interface IdentityProviderResource {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("export")
|
@Path("export")
|
||||||
public Response export(@QueryParam("format") String format);
|
Response export(@QueryParam("format") String format);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("mapper-types")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
Map<String, IdentityProviderMapperTypeRepresentation> getMapperTypes();
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("mappers")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
List<IdentityProviderMapperRepresentation> getMappers();
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("mappers")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
Response addMapper(IdentityProviderMapperRepresentation mapper);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep);
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("mappers/{id}")
|
||||||
|
void delete(@PathParam("id") String id);
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -28,14 +29,15 @@ import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pedroigor
|
* @author pedroigor
|
||||||
*/
|
*/
|
||||||
public interface IdentityProvidersResource {
|
public interface IdentityProvidersResource {
|
||||||
|
|
||||||
@Path("instances/{id}")
|
@Path("instances/{alias}")
|
||||||
IdentityProviderResource get(@PathParam("id") String id);
|
IdentityProviderResource get(@PathParam("alias") String alias);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("instances")
|
@Path("instances")
|
||||||
|
@ -46,4 +48,21 @@ public interface IdentityProvidersResource {
|
||||||
@Path("instances")
|
@Path("instances")
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
Response create(IdentityProviderRepresentation identityProvider);
|
Response create(IdentityProviderRepresentation identityProvider);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/providers/{provider_id}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
Response getIdentityProviders(@PathParam("provider_id") String providerId);
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("import-config")
|
||||||
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
Map<String, String> importFrom(MultipartFormDataOutput data);
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("import-config")
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
Map<String, String> importFrom(Map<String, Object> data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,40 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.admin;
|
package org.keycloak.testsuite.admin;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||||
|
import org.keycloak.dom.saml.v2.metadata.EndpointType;
|
||||||
|
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
|
||||||
|
import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
|
||||||
|
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
||||||
|
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
|
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||||
|
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||||
|
import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntityDescriptorParser;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
|
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -33,20 +61,28 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAll() {
|
public void testFindAll() {
|
||||||
realm.identityProviders().create(create("google", "google", "Google"));
|
Response response = realm.identityProviders().create(create("google", "google"));
|
||||||
realm.identityProviders().create(create("facebook", "facebook", "Facebook"));
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("facebook", "facebook"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
Assert.assertNames(realm.identityProviders().findAll(), "google", "facebook");
|
Assert.assertNames(realm.identityProviders().findAll(), "google", "facebook");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() {
|
public void testCreate() {
|
||||||
IdentityProviderRepresentation newIdentityProvider = create("new-identity-provider", "oidc", "New Identity Provider");
|
IdentityProviderRepresentation newIdentityProvider = create("new-identity-provider", "oidc");
|
||||||
|
|
||||||
newIdentityProvider.getConfig().put("clientId", "clientId");
|
newIdentityProvider.getConfig().put("clientId", "clientId");
|
||||||
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
|
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
|
||||||
|
|
||||||
realm.identityProviders().create(newIdentityProvider);
|
Response response = realm.identityProviders().create(newIdentityProvider);
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
IdentityProviderResource identityProviderResource = realm.identityProviders().get("new-identity-provider");
|
IdentityProviderResource identityProviderResource = realm.identityProviders().get("new-identity-provider");
|
||||||
|
|
||||||
assertNotNull(identityProviderResource);
|
assertNotNull(identityProviderResource);
|
||||||
|
@ -67,12 +103,15 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
IdentityProviderRepresentation newIdentityProvider = create("update-identity-provider", "oidc", "Update Identity Provider");
|
IdentityProviderRepresentation newIdentityProvider = create("update-identity-provider", "oidc");
|
||||||
|
|
||||||
newIdentityProvider.getConfig().put("clientId", "clientId");
|
newIdentityProvider.getConfig().put("clientId", "clientId");
|
||||||
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
|
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
|
||||||
|
|
||||||
realm.identityProviders().create(newIdentityProvider);
|
Response response = realm.identityProviders().create(newIdentityProvider);
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
|
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
|
||||||
|
|
||||||
assertNotNull(identityProviderResource);
|
assertNotNull(identityProviderResource);
|
||||||
|
@ -103,9 +142,12 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@Test(expected = NotFoundException.class)
|
@Test(expected = NotFoundException.class)
|
||||||
public void testRemove() {
|
public void testRemove() {
|
||||||
IdentityProviderRepresentation newIdentityProvider = create("remove-identity-provider", "saml", "Remove Identity Provider");
|
IdentityProviderRepresentation newIdentityProvider = create("remove-identity-provider", "saml");
|
||||||
|
|
||||||
|
Response response = realm.identityProviders().create(newIdentityProvider);
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
realm.identityProviders().create(newIdentityProvider);
|
|
||||||
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
|
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
|
||||||
|
|
||||||
assertNotNull(identityProviderResource);
|
assertNotNull(identityProviderResource);
|
||||||
|
@ -119,14 +161,384 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
||||||
realm.identityProviders().get("update-identity-provider");
|
realm.identityProviders().get("update-identity-provider");
|
||||||
}
|
}
|
||||||
|
|
||||||
private IdentityProviderRepresentation create(String id, String providerId, String name) {
|
|
||||||
IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
|
|
||||||
|
|
||||||
identityProviderRepresentation.setAlias(id);
|
private IdentityProviderRepresentation create(String id, String providerId) {
|
||||||
identityProviderRepresentation.setProviderId(providerId);
|
return create(id, providerId, null);
|
||||||
identityProviderRepresentation.setEnabled(true);
|
|
||||||
|
|
||||||
return identityProviderRepresentation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IdentityProviderRepresentation create(String id, String providerId, Map<String, String> config) {
|
||||||
|
IdentityProviderRepresentation idp = new IdentityProviderRepresentation();
|
||||||
|
|
||||||
|
idp.setAlias(id);
|
||||||
|
idp.setProviderId(providerId);
|
||||||
|
idp.setEnabled(true);
|
||||||
|
if (config != null) {
|
||||||
|
idp.setConfig(config);
|
||||||
|
}
|
||||||
|
return idp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapperTypes() {
|
||||||
|
|
||||||
|
IdentityProviderResource provider;
|
||||||
|
Map<String, IdentityProviderMapperTypeRepresentation> mapperTypes;
|
||||||
|
|
||||||
|
Response response = realm.identityProviders().create(create("google", "google"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("google");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "google-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("facebook", "facebook"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("facebook");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "facebook-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("github", "github"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("github");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "github-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("twitter", "twitter"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("twitter");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes);
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("linkedin", "linkedin"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("linkedin");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "linkedin-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("microsoft", "microsoft"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("microsoft");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "microsoft-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("stackoverflow", "stackoverflow"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("stackoverflow");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "stackoverflow-user-attribute-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("keycloak-oidc", "keycloak-oidc"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("keycloak-oidc");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "keycloak-oidc-role-to-role-idp-mapper", "oidc-user-attribute-idp-mapper", "oidc-role-idp-mapper", "oidc-username-idp-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("oidc", "oidc"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("oidc");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "oidc-user-attribute-idp-mapper", "oidc-role-idp-mapper", "oidc-username-idp-mapper");
|
||||||
|
|
||||||
|
response = realm.identityProviders().create(create("saml", "saml"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
provider = realm.identityProviders().get("saml");
|
||||||
|
mapperTypes = provider.getMapperTypes();
|
||||||
|
assertMapperTypes(mapperTypes, "saml-user-attribute-idp-mapper", "saml-role-idp-mapper", "saml-username-idp-mapper");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertMapperTypes(Map<String, IdentityProviderMapperTypeRepresentation> mapperTypes, String ... mapperIds) {
|
||||||
|
Set<String> expected = new HashSet<>();
|
||||||
|
expected.add("hardcoded-user-session-attribute-idp-mapper");
|
||||||
|
expected.add("oidc-hardcoded-role-idp-mapper");
|
||||||
|
expected.add("hardcoded-attribute-idp-mapper");
|
||||||
|
for (String id: mapperIds) {
|
||||||
|
expected.add(id);
|
||||||
|
}
|
||||||
|
Assert.assertEquals("mapperTypes", expected, mapperTypes.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoExport() {
|
||||||
|
Response response = realm.identityProviders().create(create("keycloak-oidc", "keycloak-oidc"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
response = realm.identityProviders().get("keycloak-oidc").export("json");
|
||||||
|
Assert.assertEquals("status", 204, response.getStatus());
|
||||||
|
String body = response.readEntity(String.class);
|
||||||
|
Assert.assertNull("body", body);
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSamlImportAndExport() throws URISyntaxException, IOException, ParsingException {
|
||||||
|
|
||||||
|
// Use import-config to convert IDPSSODescriptor file into key value pairs
|
||||||
|
// to use when creating a SAML Identity Provider
|
||||||
|
MultipartFormDataOutput form = new MultipartFormDataOutput();
|
||||||
|
form.addFormData("providerId", "saml", MediaType.TEXT_PLAIN_TYPE);
|
||||||
|
|
||||||
|
URL idpMeta = getClass().getClassLoader().getResource("admin-test/saml-idp-metadata.xml");
|
||||||
|
byte [] content = Files.readAllBytes(Paths.get(idpMeta.toURI()));
|
||||||
|
String body = new String(content, Charset.forName("utf-8"));
|
||||||
|
form.addFormData("file", body, MediaType.APPLICATION_XML_TYPE, "saml-idp-metadata.xml");
|
||||||
|
|
||||||
|
Map<String, String> result = realm.identityProviders().importFrom(form);
|
||||||
|
assertSamlImport(result);
|
||||||
|
|
||||||
|
// Create new SAML identity provider using configuration retrieved from import-config
|
||||||
|
Response response = realm.identityProviders().create(create("saml", "saml", result));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
IdentityProviderResource provider = realm.identityProviders().get("saml");
|
||||||
|
IdentityProviderRepresentation rep = provider.toRepresentation();
|
||||||
|
assertCreatedSamlIdp(rep);
|
||||||
|
|
||||||
|
// Now list the providers - we should see the one just created
|
||||||
|
List<IdentityProviderRepresentation> providers = realm.identityProviders().findAll();
|
||||||
|
Assert.assertNotNull("identityProviders not null", providers);
|
||||||
|
Assert.assertEquals("identityProviders instance count", 1, providers.size());
|
||||||
|
assertEqual(rep, providers.get(0));
|
||||||
|
|
||||||
|
// Perform export, and make sure some of the values are like they're supposed to be
|
||||||
|
response = realm.identityProviders().get("saml").export("xml");
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
body = response.readEntity(String.class);
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
assertSamlExport(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMappers() {
|
||||||
|
Response response = realm.identityProviders().create(create("google", "google"));
|
||||||
|
Assert.assertNotNull(ApiUtil.getCreatedId(response));
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
IdentityProviderResource provider = realm.identityProviders().get("google");
|
||||||
|
|
||||||
|
IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation();
|
||||||
|
mapper.setIdentityProviderAlias("google");
|
||||||
|
mapper.setName("my_mapper");
|
||||||
|
mapper.setIdentityProviderMapper("oidc-hardcoded-role-idp-mapper");
|
||||||
|
Map<String, String> config = new HashMap<>();
|
||||||
|
config.put("role", "offline_access");
|
||||||
|
mapper.setConfig(config);
|
||||||
|
|
||||||
|
// create and add mapper
|
||||||
|
response = provider.addMapper(mapper);
|
||||||
|
String id = ApiUtil.getCreatedId(response);
|
||||||
|
Assert.assertNotNull(id);
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
// list mappers
|
||||||
|
List<IdentityProviderMapperRepresentation> mappers = provider.getMappers();
|
||||||
|
Assert.assertEquals("mappers count", 1, mappers.size());
|
||||||
|
Assert.assertEquals("newly created mapper id", id, mappers.get(0).getId());
|
||||||
|
|
||||||
|
// get mapper
|
||||||
|
mapper = provider.getMapperById(id);
|
||||||
|
Assert.assertNotNull("mapperById not null", mapper);
|
||||||
|
Assert.assertEquals("mapper id", id, mapper.getId());
|
||||||
|
Assert.assertNotNull("mapper.config exists", mapper.getConfig());
|
||||||
|
Assert.assertEquals("config retained", "offline_access", mapper.getConfig().get("role"));
|
||||||
|
|
||||||
|
// update mapper
|
||||||
|
mapper.getConfig().put("role", "master-realm.manage-realm");
|
||||||
|
provider.update(id, mapper);
|
||||||
|
mapper = provider.getMapperById(id);
|
||||||
|
Assert.assertNotNull("mapperById not null", mapper);
|
||||||
|
Assert.assertEquals("config changed", "master-realm.manage-realm", mapper.getConfig().get("role"));
|
||||||
|
|
||||||
|
// delete mapper
|
||||||
|
provider.delete(id);
|
||||||
|
try {
|
||||||
|
provider.getMapperById(id);
|
||||||
|
Assert.fail("Should fail with NotFoundException");
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstalledIdentityProviders() {
|
||||||
|
Response response = realm.identityProviders().getIdentityProviders("oidc");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
Map<String, String> body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "oidc", "OpenID Connect v1.0");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("keycloak-oidc");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "keycloak-oidc", "Keycloak OpenID Connect");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("saml");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "saml", "SAML v2.0");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("google");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "google", "Google");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("facebook");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "facebook", "Facebook");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("github");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "github", "GitHub");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("twitter");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "twitter", "Twitter");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("linkedin");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "linkedin", "LinkedIn");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("microsoft");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "microsoft", "Microsoft");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("stackoverflow");
|
||||||
|
Assert.assertEquals("Status", 200, response.getStatus());
|
||||||
|
body = response.readEntity(Map.class);
|
||||||
|
assertProviderInfo(body, "stackoverflow", "StackOverflow");
|
||||||
|
|
||||||
|
response = realm.identityProviders().getIdentityProviders("nonexistent");
|
||||||
|
Assert.assertEquals("Status", 400, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEqual(IdentityProviderRepresentation expected, IdentityProviderRepresentation actual) {
|
||||||
|
//System.out.println("expected: " + expected);
|
||||||
|
//System.out.println("actual: " + actual);
|
||||||
|
Assert.assertNotNull("expected IdentityProviderRepresentation not null", expected);
|
||||||
|
Assert.assertNotNull("actual IdentityProviderRepresentation not null", actual);
|
||||||
|
Assert.assertEquals("internalId", expected.getInternalId(), actual.getInternalId());
|
||||||
|
Assert.assertEquals("alias", expected.getAlias(), actual.getAlias());
|
||||||
|
Assert.assertEquals("providerId", expected.getProviderId(), actual.getProviderId());
|
||||||
|
Assert.assertEquals("enabled", expected.isEnabled(), actual.isEnabled());
|
||||||
|
Assert.assertEquals("firstBrokerLoginFlowAlias", expected.getFirstBrokerLoginFlowAlias(), actual.getFirstBrokerLoginFlowAlias());
|
||||||
|
Assert.assertEquals("config", expected.getConfig(), actual.getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCreatedSamlIdp(IdentityProviderRepresentation idp) {
|
||||||
|
//System.out.println("idp: " + idp);
|
||||||
|
Assert.assertNotNull("IdentityProviderRepresentation not null", idp);
|
||||||
|
Assert.assertNotNull("internalId", idp.getInternalId());
|
||||||
|
Assert.assertEquals("alias", "saml", idp.getAlias());
|
||||||
|
Assert.assertEquals("providerId", "saml", idp.getProviderId());
|
||||||
|
Assert.assertTrue("enabled", idp.isEnabled());
|
||||||
|
Assert.assertEquals("firstBrokerLoginFlowAlias", "first broker login",idp.getFirstBrokerLoginFlowAlias());
|
||||||
|
assertSamlConfig(idp.getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSamlConfig(Map<String, String> config) {
|
||||||
|
// import endpoint simply converts IDPSSODescriptor into key value pairs.
|
||||||
|
// check that saml-idp-metadata.xml was properly converted into key value pairs
|
||||||
|
//System.out.println(config);
|
||||||
|
Assert.assertEquals("Config size", 7, config.size());
|
||||||
|
Assert.assertEquals("validateSignature", "true", config.get("validateSignature"));
|
||||||
|
Assert.assertEquals("singleLogoutServiceUrl", "http://localhost:8080/auth/realms/master/protocol/saml", config.get("singleLogoutServiceUrl"));
|
||||||
|
Assert.assertEquals("postBindingResponse", "true", config.get("postBindingResponse"));
|
||||||
|
Assert.assertEquals("postBindingAuthnRequest", "true", config.get("postBindingAuthnRequest"));
|
||||||
|
Assert.assertEquals("singleSignOnServiceUrl", "http://localhost:8080/auth/realms/master/protocol/saml", config.get("singleSignOnServiceUrl"));
|
||||||
|
Assert.assertEquals("wantAuthnRequestsSigned", "true", config.get("wantAuthnRequestsSigned"));
|
||||||
|
Assert.assertNotNull("signingCertificate not null", config.get("signingCertificate"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSamlImport(Map<String, String> config) {
|
||||||
|
assertSamlConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSamlExport(String body) throws ParsingException, URISyntaxException {
|
||||||
|
//System.out.println(body);
|
||||||
|
|
||||||
|
Object entBody = new SAMLEntityDescriptorParser().parse(StaxParserUtil.getXMLEventReader(
|
||||||
|
new ByteArrayInputStream(body.getBytes(Charset.forName("utf-8")))));
|
||||||
|
|
||||||
|
Assert.assertEquals("Parsed export type", EntityDescriptorType.class, entBody.getClass());
|
||||||
|
EntityDescriptorType entity = (EntityDescriptorType) entBody;
|
||||||
|
|
||||||
|
Assert.assertEquals("EntityID", "http://localhost:8180/auth/realms/admin-client-test", entity.getEntityID());
|
||||||
|
|
||||||
|
Assert.assertNotNull("ChoiceType not null", entity.getChoiceType());
|
||||||
|
Assert.assertEquals("ChoiceType.size", 1, entity.getChoiceType().size());
|
||||||
|
|
||||||
|
List<EntityDescriptorType.EDTDescriptorChoiceType> descriptors = entity.getChoiceType().get(0).getDescriptors();
|
||||||
|
Assert.assertNotNull("Descriptors not null", descriptors);
|
||||||
|
Assert.assertEquals("Descriptors.size", 1, descriptors.size());
|
||||||
|
|
||||||
|
SPSSODescriptorType desc = descriptors.get(0).getSpDescriptor();
|
||||||
|
Assert.assertNotNull("SPSSODescriptor not null", desc);
|
||||||
|
|
||||||
|
Assert.assertTrue("AuthnRequestsSigned", desc.isAuthnRequestsSigned());
|
||||||
|
|
||||||
|
Set<String> expected = new HashSet(Arrays.asList(
|
||||||
|
"urn:oasis:names:tc:SAML:2.0:protocol",
|
||||||
|
"urn:oasis:names:tc:SAML:1.1:protocol",
|
||||||
|
"http://schemas.xmlsoap.org/ws/2003/07/secext"));
|
||||||
|
|
||||||
|
Set<String> actual = new HashSet(desc.getProtocolSupportEnumeration());
|
||||||
|
|
||||||
|
Assert.assertEquals("ProtocolSupportEnumeration", expected, actual);
|
||||||
|
|
||||||
|
Assert.assertNotNull("AssertionConsumerService not null", desc.getAssertionConsumerService());
|
||||||
|
Assert.assertEquals("AssertionConsumerService.size", 1, desc.getAssertionConsumerService().size());
|
||||||
|
|
||||||
|
IndexedEndpointType endpoint = desc.getAssertionConsumerService().get(0);
|
||||||
|
|
||||||
|
Assert.assertEquals("AssertionConsumerService.Location",
|
||||||
|
new URI("http://localhost:8180/auth/realms/admin-client-test/broker/saml/endpoint"), endpoint.getLocation());
|
||||||
|
Assert.assertEquals("AssertionConsumerService.Binding",
|
||||||
|
new URI("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"), endpoint.getBinding());
|
||||||
|
Assert.assertTrue("AssertionConsumerService.isDefault", endpoint.isIsDefault());
|
||||||
|
|
||||||
|
|
||||||
|
Assert.assertNotNull("SingleLogoutService not null", desc.getSingleLogoutService());
|
||||||
|
Assert.assertEquals("SingleLogoutService.size", 1, desc.getSingleLogoutService().size());
|
||||||
|
|
||||||
|
EndpointType sloEndpoint = desc.getSingleLogoutService().get(0);
|
||||||
|
|
||||||
|
Assert.assertEquals("SingleLogoutService.Location",
|
||||||
|
new URI("http://localhost:8180/auth/realms/admin-client-test/broker/saml/endpoint"), sloEndpoint.getLocation());
|
||||||
|
Assert.assertEquals("SingleLogoutService.Binding",
|
||||||
|
new URI("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"), sloEndpoint.getBinding());
|
||||||
|
|
||||||
|
Assert.assertNotNull("KeyDescriptor not null", desc.getKeyDescriptor());
|
||||||
|
Assert.assertEquals("KeyDescriptor.size", 1, desc.getKeyDescriptor().size());
|
||||||
|
Assert.assertEquals("KeyDescriptor.Use", KeyTypes.SIGNING, desc.getKeyDescriptor().get(0).getUse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertProviderInfo(Map<String, String> info, String id, String name) {
|
||||||
|
System.out.println(info);
|
||||||
|
Assert.assertEquals("id", id, info.get("id"));
|
||||||
|
Assert.assertEquals("name", name, info.get("name"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<EntityDescriptor entityID="http://localhost:8080/auth/realms/master"
|
||||||
|
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<IDPSSODescriptor WantAuthnRequestsSigned="true"
|
||||||
|
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||||
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
|
||||||
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
|
||||||
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
|
||||||
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
|
||||||
|
|
||||||
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||||
|
Location="http://localhost:8080/auth/realms/master/protocol/saml" />
|
||||||
|
<SingleLogoutService
|
||||||
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||||
|
Location="http://localhost:8080/auth/realms/master/protocol/saml" />
|
||||||
|
<KeyDescriptor use="signing">
|
||||||
|
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
|
||||||
|
<dsig:X509Data>
|
||||||
|
<dsig:X509Certificate>
|
||||||
|
MIICmzCCAYMCBgFUYnC0OjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTYwNDI5MTQzMjEzWhcNMjYwNDI5MTQzMzUzWjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCN25AW1poMEZRbuMAHG58AThZmCwMV6/Gcui4mjGacRFyudgqzLjQ2rxpoW41JAtLjbjeAhuWvirUcFVcOeS3gM/ZC27qCpYighAcylZz6MYocnEe1+e8rPPk4JlID6Wv62dgu+pL/vYsQpRhvD3Y2c/ytgr5D32xF+KnzDehUy5BSyzypvu12Wq9mS5vK5tzkN37EjkhpY2ZxaXPubjDIITCAL4Q8M/m5IlacBaUZbzI4AQrHnMP1O1IH2dHSWuMiBe+xSDTco72PmuYPJKTV4wQdeBUIkYbfLc4RxVmXEvgkQgyW86EoMPxlWJpj7+mTIR+l+2thZPr/VgwTs82rAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAA/Ip/Hi8RoVu5ouaFFlc5whT7ltuK8slfLGW4tM4vJXhInYwsqIRQKBNDYW/64xle3eII4u1yAH1OYRRwEs7Em1pr4QuFuTY1at+aE0sE46XDlyESI0txJjWxYoT133vM0We2pj1b2nxgU30rwjKA3whnKEfTEYT/n3JBSqNggy6l8ZGw/oPSgvPaR4+xeB1tfQFC4VrLoYKoqH6hAL530nKxL+qV8AIfL64NDEE8ankIAEDAAFe8x3CPUfXR/p4KOANKkpz8ieQaHDb1eITkAwUwjESj6UF9D1aePlhWls/HX0gujFXtWfWfrJ8CU/ogwlH8y1jgRuLjFQYZk6llc=
|
||||||
|
</dsig:X509Certificate>
|
||||||
|
</dsig:X509Data>
|
||||||
|
</dsig:KeyInfo>
|
||||||
|
</KeyDescriptor>
|
||||||
|
</IDPSSODescriptor>
|
||||||
|
</EntityDescriptor>
|
Loading…
Reference in a new issue