/* * 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.authentication; import org.junit.Assert; import org.junit.Test; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation; import org.keycloak.testsuite.actions.DummyRequiredActionFactory; import org.keycloak.testsuite.util.AdminEventPaths; import javax.ws.rs.NotFoundException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; /** * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> */ public class RequiredActionsTest extends AbstractAuthenticationTest { @Test public void testRequiredActions() { List<RequiredActionProviderRepresentation> result = authMgmtResource.getRequiredActions(); List<RequiredActionProviderRepresentation> expected = new ArrayList<>(); addRequiredAction(expected, "CONFIGURE_TOTP", "Configure OTP", true, false, null); addRequiredAction(expected, "UPDATE_PASSWORD", "Update Password", true, false, null); addRequiredAction(expected, "UPDATE_PROFILE", "Update Profile", true, false, null); addRequiredAction(expected, "VERIFY_EMAIL", "Verify Email", true, false, null); addRequiredAction(expected, "terms_and_conditions", "Terms and Conditions", false, false, null); compareRequiredActions(expected, sort(result)); RequiredActionProviderRepresentation forUpdate = newRequiredAction("VERIFY_EMAIL", "Verify Email", false, false, null); try { authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate); Assert.fail("updateRequiredAction should fail due to null config"); } catch (Exception ignored) { } forUpdate.setConfig(Collections.<String, String>emptyMap()); authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate); assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION); result = authMgmtResource.getRequiredActions(); RequiredActionProviderRepresentation updated = findRequiredActionByAlias(forUpdate.getAlias(), result); Assert.assertNotNull("Required Action still there", updated); compareRequiredAction(forUpdate, updated); } @Test public void testCRUDRequiredAction() { // Just Dummy RequiredAction is not registered in the realm List<RequiredActionProviderSimpleRepresentation> result = authMgmtResource.getUnregisteredRequiredActions(); Assert.assertEquals(1, result.size()); RequiredActionProviderSimpleRepresentation action = result.get(0); Assert.assertEquals(DummyRequiredActionFactory.PROVIDER_ID, action.getProviderId()); Assert.assertEquals("Dummy Action", action.getName()); // Register it authMgmtResource.registerRequiredAction(action); assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION); // Try to find not-existent action - should fail try { authMgmtResource.getRequiredAction("not-existent"); Assert.fail("Didn't expect to find requiredAction of alias 'not-existent'"); } catch (NotFoundException nfe) { // Expected } // Find existent RequiredActionProviderRepresentation rep = authMgmtResource.getRequiredAction(DummyRequiredActionFactory.PROVIDER_ID); compareRequiredAction(rep, newRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, "Dummy Action", true, false, Collections.emptyMap())); // Update not-existent - should fail try { authMgmtResource.updateRequiredAction("not-existent", rep); Assert.fail("Not expected to update not-existent requiredAction"); } catch (NotFoundException nfe) { // Expected } // Update (set it as defaultAction) rep.setDefaultAction(true); authMgmtResource.updateRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, rep); assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep, ResourceType.REQUIRED_ACTION); compareRequiredAction(rep, newRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, "Dummy Action", true, true, Collections.emptyMap())); // Remove unexistent - should fail try { authMgmtResource.removeRequiredAction("not-existent"); Assert.fail("Not expected to remove not-existent requiredAction"); } catch (NotFoundException nfe) { // Expected } // Remove success authMgmtResource.removeRequiredAction(DummyRequiredActionFactory.PROVIDER_ID); assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION); } private RequiredActionProviderRepresentation findRequiredActionByAlias(String alias, List<RequiredActionProviderRepresentation> list) { for (RequiredActionProviderRepresentation a: list) { if (alias.equals(a.getAlias())) { return a; } } return null; } private List<RequiredActionProviderRepresentation> sort(List<RequiredActionProviderRepresentation> list) { ArrayList<RequiredActionProviderRepresentation> sorted = new ArrayList<>(list); Collections.sort(sorted, new RequiredActionProviderComparator()); return sorted; } private void compareRequiredActions(List<RequiredActionProviderRepresentation> expected, List<RequiredActionProviderRepresentation> actual) { Assert.assertNotNull("Actual null", actual); Assert.assertEquals("Required actions count", expected.size(), actual.size()); Iterator<RequiredActionProviderRepresentation> ite = expected.iterator(); Iterator<RequiredActionProviderRepresentation> ita = actual.iterator(); while (ite.hasNext()) { compareRequiredAction(ite.next(), ita.next()); } } private void compareRequiredAction(RequiredActionProviderRepresentation expected, RequiredActionProviderRepresentation actual) { Assert.assertEquals("alias - " + expected.getAlias(), expected.getAlias(), actual.getAlias()); Assert.assertEquals("name - " + expected.getAlias(), expected.getName(), actual.getName()); Assert.assertEquals("enabled - " + expected.getAlias(), expected.isEnabled(), actual.isEnabled()); Assert.assertEquals("defaultAction - " + expected.getAlias(), expected.isDefaultAction(), actual.isDefaultAction()); Assert.assertEquals("config - " + expected.getAlias(), expected.getConfig() != null ? expected.getConfig() : Collections.emptyMap(), actual.getConfig()); } private void addRequiredAction(List<RequiredActionProviderRepresentation> target, String alias, String name, boolean enabled, boolean defaultAction, Map conf) { target.add(newRequiredAction(alias, name, enabled, defaultAction, conf)); } private RequiredActionProviderRepresentation newRequiredAction(String alias, String name, boolean enabled, boolean defaultAction, Map conf) { RequiredActionProviderRepresentation action = new RequiredActionProviderRepresentation(); action.setAlias(alias); action.setName(name); action.setEnabled(enabled); action.setDefaultAction(defaultAction); action.setConfig(conf); return action; } private static class RequiredActionProviderComparator implements Comparator<RequiredActionProviderRepresentation> { @Override public int compare(RequiredActionProviderRepresentation o1, RequiredActionProviderRepresentation o2) { return o1.getAlias().compareTo(o2.getAlias()); } } }