/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.testsuite.admin; import org.junit.Before; import org.junit.Test; import org.keycloak.admin.client.resource.ComponentsResource; import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.representations.idm.AdminEventRepresentation; import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.ErrorRepresentation; import org.keycloak.testsuite.components.TestProvider; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import static org.junit.Assert.*; /** * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> */ public class ComponentsTest extends AbstractAdminTest { private ComponentsResource components; @Before public void before() throws Exception { components = adminClient.realm(REALM_NAME).components(); } @Test public void testNotDeadlocked() { for (int i = 0; i < 50; i++) { ComponentRepresentation rep = createComponentRepresentation("test-" + i); rep.getConfig().putSingle("required", "required-value"); createComponent(rep); List<ComponentRepresentation> list = realm.components().query(realmId, TestProvider.class.getName()); assertEquals(i + 1, list.size()); } } @Test public void testCreateValidation() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); // Check validation is invoked try { createComponent(rep); } catch (WebApplicationException e) { assertErrror(e.getResponse(), "'Required' is required"); } rep.getConfig().putSingle("required", "Required"); rep.getConfig().putSingle("number", "invalid"); // Check validation is invoked try { createComponent(rep); } catch (WebApplicationException e) { assertErrror(e.getResponse(), "'Number' should be a number"); } } @Test public void testCreateEmptyValues() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("required", "foo"); rep.getConfig().addFirst("val1", ""); rep.getConfig().put("val2", null); rep.getConfig().put("val3", Collections.emptyList()); String id = createComponent(rep); ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals( "foo", returned.getSubType()); assertEquals(1, returned.getConfig().size()); assertTrue(returned.getConfig().containsKey("required")); } @Test public void testCreateWithoutGivenId() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("required", "foo"); rep.setId(null); String id = createComponent(rep); assertNotNull(id); } @Test public void testCreateWithGivenId() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("required", "foo"); rep.setId("fixed-id"); String id = createComponent(rep); assertEquals("fixed-id", id); } @Test public void testUpdate() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("required", "foo"); rep.getConfig().addFirst("val1", "one"); rep.getConfig().addFirst("val2", "two"); rep.getConfig().addFirst("val3", "three"); String id = createComponent(rep); ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals(4, returned.getConfig().size()); assertEquals("foo", returned.getConfig().getFirst("required")); assertEquals("one", returned.getConfig().getFirst("val1")); assertEquals("two", returned.getConfig().getFirst("val2")); assertEquals("three", returned.getConfig().getFirst("val3")); // Check value updated returned.getConfig().putSingle("val1", "one-updated"); // Check null deletes property returned.getConfig().putSingle("val2", null); components.component(id).update(returned); returned = components.component(id).toRepresentation(); assertEquals(3, returned.getConfig().size()); assertEquals("one-updated", returned.getConfig().getFirst("val1")); assertFalse(returned.getConfig().containsKey("val2")); // Check empty string is deleted returned.getConfig().addFirst("val1", ""); components.component(id).update(returned); returned = components.component(id).toRepresentation(); assertEquals(2, returned.getConfig().size()); // Check empty list removes property returned.getConfig().put("val3", Collections.emptyList()); components.component(id).update(returned); returned = components.component(id).toRepresentation(); assertEquals(1, returned.getConfig().size()); } @Test public void testRename() { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("required", "foo"); String id = createComponent(rep); ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals("mycomponent", returned.getName()); rep.setName("myupdatedcomponent"); components.component(id).update(rep); returned = components.component(id).toRepresentation(); assertEquals("myupdatedcomponent", returned.getName()); } @Test public void testSecretConfig() throws Exception { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); rep.getConfig().addFirst("secret", "some secret value!!"); rep.getConfig().addFirst("required", "some required value"); String id = createComponent(rep); // Check secret value is not returned ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals(ComponentRepresentation.SECRET_VALUE, returned.getConfig().getFirst("secret")); // Check secret not leaked in admin events AdminEventRepresentation event = testingClient.testing().pollAdminEvent(); assertFalse(event.getRepresentation().contains("some secret value!!")); assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE)); Map<String, TestProvider.DetailsRepresentation> details = testingClient.testing(REALM_NAME).getTestComponentDetails(); // Check value is set correctly assertEquals("some secret value!!", details.get("mycomponent").getConfig().get("secret").get(0)); returned.getConfig().putSingle("priority", "200"); components.component(id).update(returned); ComponentRepresentation returned2 = components.component(id).toRepresentation(); assertEquals(ComponentRepresentation.SECRET_VALUE, returned2.getConfig().getFirst("secret")); // Check secret not leaked in admin events event = testingClient.testing().pollAdminEvent(); assertFalse(event.getRepresentation().contains("some secret value!!")); assertTrue(event.getRepresentation().contains(ComponentRepresentation.SECRET_VALUE)); // Check secret value is not set to '*********' details = testingClient.testing(REALM_NAME).getTestComponentDetails(); assertEquals("some secret value!!", details.get("mycomponent").getConfig().get("secret").get(0)); returned2.getConfig().putSingle("secret", "updated secret value!!"); components.component(id).update(returned2); // Check secret value is updated details = testingClient.testing(REALM_NAME).getTestComponentDetails(); assertEquals("updated secret value!!", details.get("mycomponent").getConfig().get("secret").get(0)); ComponentRepresentation returned3 = components.query().stream().filter(c -> c.getId().equals(returned2.getId())).findFirst().get(); assertEquals(ComponentRepresentation.SECRET_VALUE, returned3.getConfig().getFirst("secret")); } @Test public void testLongValueInComponentConfigAscii() throws Exception { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); String value = StringUtils.repeat("0123456789", 400); // 4000 8-bit characters rep.getConfig().addFirst("required", "foo"); rep.getConfig().addFirst("val1", value); String id = createComponent(rep); ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals(value, returned.getConfig().getFirst("val1")); } @Test public void testLongValueInComponentConfigExtLatin() throws Exception { ComponentRepresentation rep = createComponentRepresentation("mycomponent"); String value = StringUtils.repeat("ěščřžýíŮÍÁ", 400); // 4000 Unicode extended-Latin characters rep.getConfig().addFirst("required", "foo"); rep.getConfig().addFirst("val1", value); String id = createComponent(rep); ComponentRepresentation returned = components.component(id).toRepresentation(); assertEquals(value, returned.getConfig().getFirst("val1")); } private String createComponent(ComponentRepresentation rep) { ComponentsResource components = realm.components(); Response response = components.add(rep); String id = ApiUtil.getCreatedId(response); getCleanup().addComponentId(id); response.close(); return id; } private void assertErrror(Response response, String error) { if (!response.hasEntity()) { fail("No error message set"); } ErrorRepresentation errorRepresentation = response.readEntity(ErrorRepresentation.class); assertEquals(error, errorRepresentation.getErrorMessage()); } private ComponentRepresentation createComponentRepresentation(String name) { ComponentRepresentation rep = new ComponentRepresentation(); rep.setName(name); rep.setParentId(realmId); rep.setProviderId("test"); rep.setProviderType(TestProvider.class.getName()); rep.setSubType("foo"); MultivaluedHashMap config = new MultivaluedHashMap(); rep.setConfig(config); return rep; } }