Merge pull request #2809 from mposolda/master

KEYCLOAK-2862 AuthenticationManagementResource tests
This commit is contained in:
Marek Posolda 2016-05-06 21:29:35 +02:00
commit 43b51d4a30
17 changed files with 559 additions and 57 deletions

View file

@ -0,0 +1,46 @@
/*
* 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.representations.idm;
/**
* Some endpoints (like register new required action) doesn't support all the fields (like setEnabled etc).
* So this is just simplified version of full RequiredActionProviderRepresentation
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RequiredActionProviderSimpleRepresentation {
private String name;
private String providerId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
}

View file

@ -24,6 +24,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@ -127,22 +128,17 @@ public interface AuthenticationManagementResource {
@Path("/executions/{executionId}/config") @Path("/executions/{executionId}/config")
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigRepresentation config); Response newExecutionConfig(@PathParam("executionId") String executionId, AuthenticatorConfigRepresentation config);
@Path("/executions/{executionId}/config/{id}")
@GET
@Produces(MediaType.APPLICATION_JSON)
AuthenticatorConfigRepresentation getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id);
@Path("unregistered-required-actions") @Path("unregistered-required-actions")
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
List<Map<String, String>> getUnregisteredRequiredActions(); List<RequiredActionProviderSimpleRepresentation> getUnregisteredRequiredActions();
@Path("register-required-action") @Path("register-required-action")
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
void registereRequiredAction(Map<String, String> data); void registerRequiredAction(RequiredActionProviderSimpleRepresentation action);
@Path("required-actions") @Path("required-actions")
@GET @GET
@ -161,7 +157,7 @@ public interface AuthenticationManagementResource {
@Path("required-actions/{alias}") @Path("required-actions/{alias}")
@DELETE @DELETE
void updateRequiredAction(@PathParam("alias") String alias); void removeRequiredAction(@PathParam("alias") String alias);
@Path("config-description/{providerId}") @Path("config-description/{providerId}")
@GET @GET
@ -173,11 +169,6 @@ public interface AuthenticationManagementResource {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription(); Map<String, List<ConfigPropertyRepresentation>> getPerClientConfigDescription();
@Path("config")
@POST
@Consumes(MediaType.APPLICATION_JSON)
Response createAuthenticatorConfig(AuthenticatorConfigRepresentation config);
@Path("config/{id}") @Path("config/{id}")
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)

View file

@ -701,6 +701,7 @@ public class AuthenticationManagementResource {
* *
* @param execution Execution id * @param execution Execution id
* @param id Configuration id * @param id Configuration id
* @deprecated Use rather {@link #getAuthenticatorConfig(String)}
*/ */
@Path("/executions/{executionId}/config/{id}") @Path("/executions/{executionId}/config/{id}")
@GET @GET
@ -760,7 +761,7 @@ public class AuthenticationManagementResource {
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@NoCache @NoCache
public void registereRequiredAction(Map<String, String> data) { public void registerRequiredAction(Map<String, String> data) {
auth.requireManage(); auth.requireManage();
String providerId = data.get("providerId"); String providerId = data.get("providerId");
@ -857,7 +858,7 @@ public class AuthenticationManagementResource {
*/ */
@Path("required-actions/{alias}") @Path("required-actions/{alias}")
@DELETE @DELETE
public void updateRequiredAction(@PathParam("alias") String alias) { public void removeRequiredAction(@PathParam("alias") String alias) {
auth.requireManage(); auth.requireManage();
RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias); RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
@ -937,6 +938,7 @@ public class AuthenticationManagementResource {
/** /**
* Create new authenticator configuration * Create new authenticator configuration
* @param rep JSON describing new authenticator configuration * @param rep JSON describing new authenticator configuration
* @deprecated Use {@link #newExecutionConfig(String, AuthenticatorConfigRepresentation)} instead
*/ */
@Path("config") @Path("config")
@POST @POST

View file

@ -28,6 +28,9 @@ import org.keycloak.models.KeycloakSessionFactory;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class DummyRequiredActionFactory implements RequiredActionFactory { public class DummyRequiredActionFactory implements RequiredActionFactory {
public static final String PROVIDER_ID = "dummy-action";
@Override @Override
public String getDisplayText() { public String getDisplayText() {
return "Dummy Action"; return "Dummy Action";
@ -55,6 +58,6 @@ public class DummyRequiredActionFactory implements RequiredActionFactory {
@Override @Override
public String getId() { public String getId() {
return "dummy-action"; return PROVIDER_ID;
} }
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.testsuite; package org.keycloak.testsuite;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
@ -27,6 +28,7 @@ import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentat
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -74,4 +76,34 @@ public class Assert extends org.junit.Assert {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
/**
* Assert all the fields from map available. Array "expected" contains pairs when first value from pair is expected key
* and second is the expected value from the map for target key.
*
* Example config = {"key1" -> "value1" , "key2" -> "value2" }
* then assertMap(config, "key1", "value1", "key2", "value2" will return true
*
*/
public static void assertMap(Map<String, String> config, String... expected) {
if (expected == null) {
expected = new String[] {};
}
Assert.assertEquals(config.size() * 2, expected.length);
for (int i=0 ; i<expected.length ; i+=2) {
String key = expected[i];
String value = expected[i+1];
Assert.assertEquals(value, config.get(key));
}
}
public static void assertProviderConfigProperty(ConfigPropertyRepresentation property, String name, String label, String defaultValue, String helpText, String type) {
Assert.assertEquals(name, property.getName());
Assert.assertEquals(label, property.getLabel());
Assert.assertEquals(defaultValue, property.getDefaultValue());
Assert.assertEquals(helpText, property.getHelpText());
Assert.assertEquals(type, property.getType());
}
} }

View file

@ -18,8 +18,7 @@
package org.keycloak.testsuite.account.custom; package org.keycloak.testsuite.account.custom;
import java.util.List; import java.util.List;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import org.junit.Before; import org.junit.Before;
import org.keycloak.admin.client.resource.AuthenticationManagementResource; import org.keycloak.admin.client.resource.AuthenticationManagementResource;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;

View file

@ -38,6 +38,7 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation; import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserFederationMapperRepresentation; import org.keycloak.representations.idm.UserFederationMapperRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation; import org.keycloak.representations.idm.UserFederationProviderRepresentation;
@ -349,16 +350,14 @@ public class PermissionsTest extends AbstractKeycloakTest {
invoke((realm) -> { realm.flows().lowerPriority("nosuch"); }, Resource.REALM, true); invoke((realm) -> { realm.flows().lowerPriority("nosuch"); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().removeExecution("nosuch"); }, Resource.REALM, true); invoke((realm) -> { realm.flows().removeExecution("nosuch"); }, Resource.REALM, true);
invoke((realm, response) -> { response.set(realm.flows().newExecutionConfig("nosuch", new AuthenticatorConfigRepresentation())); }, Resource.REALM, true); invoke((realm, response) -> { response.set(realm.flows().newExecutionConfig("nosuch", new AuthenticatorConfigRepresentation())); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().getAuthenticatorConfig("nosuch", "nosuch"); }, Resource.REALM, false);
invoke((realm) -> { realm.flows().getUnregisteredRequiredActions(); }, Resource.REALM, false); invoke((realm) -> { realm.flows().getUnregisteredRequiredActions(); }, Resource.REALM, false);
invoke((realm) -> { realm.flows().registereRequiredAction(new HashMap<>()); }, Resource.REALM, true); invoke((realm) -> { realm.flows().registerRequiredAction(new RequiredActionProviderSimpleRepresentation()); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().getRequiredActions(); }, Resource.REALM, false, true); invoke((realm) -> { realm.flows().getRequiredActions(); }, Resource.REALM, false, true);
invoke((realm) -> { realm.flows().getRequiredAction("nosuch"); }, Resource.REALM, false); invoke((realm) -> { realm.flows().getRequiredAction("nosuch"); }, Resource.REALM, false);
invoke((realm) -> { realm.flows().updateRequiredAction("nosuch"); }, Resource.REALM, true); invoke((realm) -> { realm.flows().removeRequiredAction("nosuch"); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().updateRequiredAction("nosuch", new RequiredActionProviderRepresentation()); }, Resource.REALM, true); invoke((realm) -> { realm.flows().updateRequiredAction("nosuch", new RequiredActionProviderRepresentation()); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().getAuthenticatorConfigDescription("nosuch"); }, Resource.REALM, false); invoke((realm) -> { realm.flows().getAuthenticatorConfigDescription("nosuch"); }, Resource.REALM, false);
invoke((realm) -> { realm.flows().getPerClientConfigDescription(); }, Resource.REALM, false, true); invoke((realm) -> { realm.flows().getPerClientConfigDescription(); }, Resource.REALM, false, true);
invoke((realm, response) -> { response.set(realm.flows().createAuthenticatorConfig(new AuthenticatorConfigRepresentation())); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().getAuthenticatorConfig("nosuch"); }, Resource.REALM, false); invoke((realm) -> { realm.flows().getAuthenticatorConfig("nosuch"); }, Resource.REALM, false);
invoke((realm) -> { realm.flows().removeAuthenticatorConfig("nosuch"); }, Resource.REALM, true); invoke((realm) -> { realm.flows().removeAuthenticatorConfig("nosuch"); }, Resource.REALM, true);
invoke((realm) -> { realm.flows().updateAuthenticatorConfig("nosuch", new AuthenticatorConfigRepresentation()); }, Resource.REALM, true); invoke((realm) -> { realm.flows().updateAuthenticatorConfig("nosuch", new AuthenticatorConfigRepresentation()); }, Resource.REALM, true);

View file

@ -270,15 +270,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
Assert.assertEquals("ldap-1", rep.getFederationProviderDisplayName()); Assert.assertEquals("ldap-1", rep.getFederationProviderDisplayName());
Assert.assertEquals(federationMapperType, rep.getFederationMapperType()); Assert.assertEquals(federationMapperType, rep.getFederationMapperType());
if (config == null) { Assert.assertMap(rep.getConfig(), config);
config = new String[] {};
}
Assert.assertEquals(rep.getConfig().size() * 2, config.length);
for (int i=0 ; i<config.length ; i+=2) {
String key = config[i];
String value = config[i+1];
Assert.assertEquals(value, rep.getConfig().get(key));
}
} }
private UserFederationMapperRepresentation findMapperByName(List<UserFederationMapperRepresentation> mappers, String name) { private UserFederationMapperRepresentation findMapperByName(List<UserFederationMapperRepresentation> mappers, String name) {

View file

@ -31,7 +31,6 @@ import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation; import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation; import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation; import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
@ -65,8 +64,8 @@ public class UserFederationTest extends AbstractAdminTest {
Assert.assertTrue(dummyConfiguredProvider.getOptions() == null || dummyConfiguredProvider.getOptions().isEmpty()); Assert.assertTrue(dummyConfiguredProvider.getOptions() == null || dummyConfiguredProvider.getOptions().isEmpty());
Assert.assertEquals("Dummy User Federation Provider Help Text", dummyConfiguredProvider.getHelpText()); Assert.assertEquals("Dummy User Federation Provider Help Text", dummyConfiguredProvider.getHelpText());
Assert.assertEquals(2, dummyConfiguredProvider.getProperties().size()); Assert.assertEquals(2, dummyConfiguredProvider.getProperties().size());
assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(0), "prop1", "Prop1", "prop1Default", "Prop1 HelpText", ProviderConfigProperty.STRING_TYPE); Assert.assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(0), "prop1", "Prop1", "prop1Default", "Prop1 HelpText", ProviderConfigProperty.STRING_TYPE);
assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(1), "prop2", "Prop2", "true", "Prop2 HelpText", ProviderConfigProperty.BOOLEAN_TYPE); Assert.assertProviderConfigProperty(dummyConfiguredProvider.getProperties().get(1), "prop2", "Prop2", "true", "Prop2 HelpText", ProviderConfigProperty.BOOLEAN_TYPE);
try { try {
userFederation().getProviderFactory("not-existent"); userFederation().getProviderFactory("not-existent");
@ -80,14 +79,6 @@ public class UserFederationTest extends AbstractAdminTest {
return realm.userFederation(); return realm.userFederation();
} }
private void assertProviderConfigProperty(ConfigPropertyRepresentation property, String name, String label, String defaultValue, String helpText, String type) {
Assert.assertEquals(name, property.getName());
Assert.assertEquals(label, property.getLabel());
Assert.assertEquals(defaultValue, property.getDefaultValue());
Assert.assertEquals(helpText, property.getHelpText());
Assert.assertEquals(type, property.getType());
}
@Test @Test
public void testCreateProvider() { public void testCreateProvider() {
@ -332,16 +323,8 @@ public class UserFederationTest extends AbstractAdminTest {
Assert.assertEquals(fullSyncPeriod, rep.getFullSyncPeriod()); Assert.assertEquals(fullSyncPeriod, rep.getFullSyncPeriod());
Assert.assertEquals(changeSyncPeriod, rep.getChangedSyncPeriod()); Assert.assertEquals(changeSyncPeriod, rep.getChangedSyncPeriod());
Assert.assertEquals(lastSync, rep.getLastSync()); Assert.assertEquals(lastSync, rep.getLastSync());
if (config == null) {
config = new String[] {};
}
Assert.assertEquals(rep.getConfig().size() * 2, config.length); Assert.assertMap(rep.getConfig(), config);
for (int i=0 ; i<config.length ; i+=2) {
String key = config[i];
String value = config[i+1];
Assert.assertEquals(value, rep.getConfig().get(key));
}
} }

View file

@ -0,0 +1,179 @@
/*
* 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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator;
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.ApiUtil;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
private String executionId;
@Before
public void beforeConfigTest() {
Response response = authMgmtResource.createFlow(newFlow("firstBrokerLogin2", "firstBrokerLogin2", "basic-flow", true, false));
Assert.assertEquals(201, response.getStatus());
response.close();
HashMap<String, String> params = new HashMap<>();
params.put("provider", IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
authMgmtResource.addExecution("firstBrokerLogin2", params);
List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("firstBrokerLogin2");
AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, executionReps);
Assert.assertNotNull(exec);
executionId = exec.getId();
}
@Override
public void afterAbstractKeycloakTest() {
AuthenticationFlowRepresentation flowRep = findFlowByAlias("firstBrokerLogin2", authMgmtResource.getFlows());
authMgmtResource.deleteFlow(flowRep.getId());
}
@Test
public void testCreateConfig() {
AuthenticatorConfigRepresentation cfg = newConfig("foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
// Attempt to create config for non-existent execution
Response response = authMgmtResource.newExecutionConfig("exec-id-doesnt-exists", cfg);
Assert.assertEquals(404, response.getStatus());
response.close();
// Create config success
String cfgId = createConfig(executionId, cfg);
// Assert found
AuthenticatorConfigRepresentation cfgRep = authMgmtResource.getAuthenticatorConfig(cfgId);
assertConfig(cfgRep, cfgId, "foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
// Cleanup
authMgmtResource.removeAuthenticatorConfig(cfgId);
}
@Test
public void testUpdateConfig() {
AuthenticatorConfigRepresentation cfg = newConfig("foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
String cfgId = createConfig(executionId, cfg);
AuthenticatorConfigRepresentation cfgRep = authMgmtResource.getAuthenticatorConfig(cfgId);
// Try to update not existent config
try {
authMgmtResource.updateAuthenticatorConfig("not-existent", cfgRep);
Assert.fail("Config didn't found");
} catch (NotFoundException nfe) {
// Expected
}
// Assert nothing changed
cfgRep = authMgmtResource.getAuthenticatorConfig(cfgId);
assertConfig(cfgRep, cfgId, "foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
// Update success
cfgRep.setAlias("foo2");
cfgRep.getConfig().put("configKey2", "configValue2");
authMgmtResource.updateAuthenticatorConfig(cfgRep.getId(), cfgRep);
// Assert updated
cfgRep = authMgmtResource.getAuthenticatorConfig(cfgRep.getId());
assertConfig(cfgRep, cfgId, "foo2",
IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true",
"configKey2", "configValue2");
}
@Test
public void testRemoveConfig() {
AuthenticatorConfigRepresentation cfg = newConfig("foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
String cfgId = createConfig(executionId, cfg);
AuthenticatorConfigRepresentation cfgRep = authMgmtResource.getAuthenticatorConfig(cfgId);
// Assert execution has our config
AuthenticationExecutionInfoRepresentation execution = findExecutionByProvider(
IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, authMgmtResource.getExecutions("firstBrokerLogin2"));
Assert.assertEquals(cfgRep.getId(), execution.getAuthenticationConfig());
// Test remove not-existent
try {
authMgmtResource.removeAuthenticatorConfig("not-existent");
Assert.fail("Config didn't found");
} catch (NotFoundException nfe) {
// Expected
}
// Test remove our config
authMgmtResource.removeAuthenticatorConfig(cfgRep.getId());
// Assert config not found
try {
authMgmtResource.getAuthenticatorConfig(cfgRep.getId());
Assert.fail("Not expected to find config");
} catch (NotFoundException nfe) {
// Expected
}
// Assert execution doesn't have our config
execution = findExecutionByProvider(
IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, authMgmtResource.getExecutions("firstBrokerLogin2"));
Assert.assertNull(execution.getAuthenticationConfig());
}
private String createConfig(String executionId, AuthenticatorConfigRepresentation cfg) {
Response resp = authMgmtResource.newExecutionConfig(executionId, cfg);
Assert.assertEquals(201, resp.getStatus());
String cfgId = ApiUtil.getCreatedId(resp);
Assert.assertNotNull(cfgId);
return cfgId;
}
private AuthenticatorConfigRepresentation newConfig(String alias, String cfgKey, String cfgValue) {
AuthenticatorConfigRepresentation cfg = new AuthenticatorConfigRepresentation();
cfg.setAlias(alias);
Map<String, String> cfgMap = new HashMap<>();
cfgMap.put(cfgKey, cfgValue);
cfg.setConfig(cfgMap);
return cfg;
}
private void assertConfig(AuthenticatorConfigRepresentation cfgRep, String id, String alias, String... fields) {
Assert.assertEquals(id, cfgRep.getId());
Assert.assertEquals(alias, cfgRep.getAlias());
Assert.assertMap(cfgRep.getConfig(), fields);
}
}

View file

@ -19,15 +19,19 @@ package org.keycloak.testsuite.admin.authentication;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.authentication.AuthenticationFlow;
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.GenericType; import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@ -44,6 +48,15 @@ public class ExecutionTest extends AbstractAuthenticationTest {
authMgmtResource.addExecution("browser", params); authMgmtResource.addExecution("browser", params);
Assert.fail("add execution to built-in flow should fail"); Assert.fail("add execution to built-in flow should fail");
} catch (BadRequestException expected) { } catch (BadRequestException expected) {
// Expected
}
// try add execution to not-existent flow
try {
authMgmtResource.addExecution("not-existent", params);
Assert.fail("add execution to not-existent flow should fail");
} catch (BadRequestException expected) {
// Expected
} }
// copy built-in flow so we get a new editable flow // copy built-in flow so we get a new editable flow
@ -95,6 +108,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
rep.setAuthenticator("auth-cookie"); rep.setAuthenticator("auth-cookie");
rep.setRequirement(OPTIONAL); rep.setRequirement(OPTIONAL);
// Should fail - missing parent flow
response = authMgmtResource.addExecution(rep); response = authMgmtResource.addExecution(rep);
try { try {
Assert.assertEquals("added execution missing parent flow", 400, response.getStatus()); Assert.assertEquals("added execution missing parent flow", 400, response.getStatus());
@ -102,6 +116,25 @@ public class ExecutionTest extends AbstractAuthenticationTest {
response.close(); response.close();
} }
// Should fail - not existent parent flow
rep.setParentFlow("not-existent-id");
response = authMgmtResource.addExecution(rep);
try {
Assert.assertEquals("added execution missing parent flow", 400, response.getStatus());
} finally {
response.close();
}
// Should fail - add execution to builtin flow
AuthenticationFlowRepresentation browserFlow = findFlowByAlias("browser", authMgmtResource.getFlows());
rep.setParentFlow(browserFlow.getId());
response = authMgmtResource.addExecution(rep);
try {
Assert.assertEquals("added execution to builtin flow", 400, response.getStatus());
} finally {
response.close();
}
// get Copy of browser flow id, and set it on execution // get Copy of browser flow id, and set it on execution
List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows(); List<AuthenticationFlowRepresentation> flows = authMgmtResource.getFlows();
AuthenticationFlowRepresentation flow = findFlowByAlias("Copy of browser", flows); AuthenticationFlowRepresentation flow = findFlowByAlias("Copy of browser", flows);
@ -145,4 +178,70 @@ public class ExecutionTest extends AbstractAuthenticationTest {
AuthenticationExecutionInfoRepresentation exec2 = findExecutionByProvider("auth-cookie", executionReps); AuthenticationExecutionInfoRepresentation exec2 = findExecutionByProvider("auth-cookie", executionReps);
compareExecution(exec, exec2); compareExecution(exec, exec2);
} }
@Test
public void testClientFlowExecutions() {
// Create client flow
AuthenticationFlowRepresentation clientFlow = newFlow("new-client-flow", "desc", AuthenticationFlow.CLIENT_FLOW, true, false);
Response response = authMgmtResource.createFlow(clientFlow);
Assert.assertEquals(201, response.getStatus());
response.close();
// Add execution to it
Map<String, String> executionData = new HashMap<>();
executionData.put("provider", ClientIdAndSecretAuthenticator.PROVIDER_ID);
authMgmtResource.addExecution("new-client-flow", executionData);
// Check executions of not-existent flow - SHOULD FAIL
try {
authMgmtResource.getExecutions("not-existent");
Assert.fail("Not expected to find executions");
} catch (NotFoundException nfe) {
// Expected
}
// Check existent executions
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("new-client-flow");
AuthenticationExecutionInfoRepresentation executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, executions);
Assert.assertNotNull(executionRep);
// Update execution with not-existent flow - SHOULD FAIL
try {
authMgmtResource.updateExecutions("not-existent", executionRep);
Assert.fail("Not expected to update execution with not-existent flow");
} catch (NotFoundException nfe) {
// Expected
}
// Update execution with not-existent ID - SHOULD FAIL
try {
AuthenticationExecutionInfoRepresentation executionRep2 = new AuthenticationExecutionInfoRepresentation();
executionRep2.setId("not-existent");
authMgmtResource.updateExecutions("new-client-flow", executionRep2);
Assert.fail("Not expected to update not-existent execution");
} catch (NotFoundException nfe) {
// Expected
}
// Update success
executionRep.setRequirement(ALTERNATIVE);
authMgmtResource.updateExecutions("new-client-flow", executionRep);
// Check updated
executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, authMgmtResource.getExecutions("new-client-flow"));
Assert.assertEquals(ALTERNATIVE, executionRep.getRequirement());
// Remove execution with not-existent ID
try {
authMgmtResource.removeExecution("not-existent");
Assert.fail("Didn't expect to find execution");
} catch (NotFoundException nfe) {
// Expected
}
// Successfuly remove execution and flow
authMgmtResource.removeExecution(executionRep.getId());
AuthenticationFlowRepresentation rep = findFlowByAlias("new-client-flow", authMgmtResource.getFlows());
authMgmtResource.deleteFlow(rep.getId());
}
} }

View file

@ -23,6 +23,7 @@ import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentat
import org.keycloak.representations.idm.AuthenticationFlowRepresentation; import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -55,6 +56,15 @@ public class FlowTest extends AbstractAuthenticationTest {
response.close(); response.close();
} }
// try create flow without alias
response = authMgmtResource.createFlow(newFlow(null, "Browser flow", "basic-flow", true, false));
try {
Assert.assertEquals("createFlow using the alias of existing flow should fail", 409, response.getStatus());
} finally {
response.close();
}
// create new flow that should succeed // create new flow that should succeed
AuthenticationFlowRepresentation newFlow = newFlow("browser-2", "Browser flow", "basic-flow", true, false); AuthenticationFlowRepresentation newFlow = newFlow("browser-2", "Browser flow", "basic-flow", true, false);
response = authMgmtResource.createFlow(newFlow); response = authMgmtResource.createFlow(newFlow);
@ -71,25 +81,46 @@ public class FlowTest extends AbstractAuthenticationTest {
Assert.assertNotNull("created flow visible in parent", found); Assert.assertNotNull("created flow visible in parent", found);
compareFlows(newFlow, found); compareFlows(newFlow, found);
// check lookup flow with unexistent ID
try {
authMgmtResource.getFlow("id-123-notExistent");
Assert.fail("Not expected to find unexistent flow");
} catch (NotFoundException nfe) {
// Expected
}
// check that new flow is returned individually // check that new flow is returned individually
AuthenticationFlowRepresentation found2 = authMgmtResource.getFlow(found.getId()); AuthenticationFlowRepresentation found2 = authMgmtResource.getFlow(found.getId());
Assert.assertNotNull("created flow visible directly", found2); Assert.assertNotNull("created flow visible directly", found2);
compareFlows(newFlow, found2); compareFlows(newFlow, found2);
// add execution flow using a different method // add execution flow to some parent flow
Map<String, String> data = new HashMap<>(); Map<String, String> data = new HashMap<>();
data.put("alias", "SomeFlow"); data.put("alias", "SomeFlow");
data.put("type", "basic-flow"); data.put("type", "basic-flow");
data.put("description", "Test flow"); data.put("description", "Test flow");
data.put("provider", "registration-page-form"); data.put("provider", "registration-page-form");
// inexistent parent flow - should fail
try { try {
authMgmtResource.addExecutionFlow("inexistent-parent-flow-alias", data); authMgmtResource.addExecutionFlow("inexistent-parent-flow-alias", data);
Assert.fail("addExecutionFlow for inexistent parent should have failed"); Assert.fail("addExecutionFlow for inexistent parent should have failed");
} catch (Exception expected) { } catch (Exception expected) {
// Expected
} }
// already existent flow - should fail
try {
data.put("alias", "browser");
authMgmtResource.addExecutionFlow("browser-2", data);
Assert.fail("addExecutionFlow should have failed as browser flow already exists");
} catch (Exception expected) {
// Expected
}
// Successfully add flow
data.put("alias", "SomeFlow");
authMgmtResource.addExecutionFlow("browser-2", data); authMgmtResource.addExecutionFlow("browser-2", data);
// check that new flow is returned in a children list // check that new flow is returned in a children list
@ -117,6 +148,14 @@ public class FlowTest extends AbstractAuthenticationTest {
flows = authMgmtResource.getFlows(); flows = authMgmtResource.getFlows();
found = findFlowByAlias("browser-2", flows); found = findFlowByAlias("browser-2", flows);
Assert.assertNull("flow deleted", found); Assert.assertNull("flow deleted", found);
// Check deleting flow second time will fail
try {
authMgmtResource.deleteFlow("id-123-notExistent");
Assert.fail("Not expected to delete flow, which doesn't exists");
} catch (NotFoundException nfe) {
// Expected
}
} }

View file

@ -61,7 +61,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
// separately load referenced configurations // separately load referenced configurations
String configId = exec.getAuthenticationConfig(); String configId = exec.getAuthenticationConfig();
if (configId != null && !configs.containsKey(configId)) { if (configId != null && !configs.containsKey(configId)) {
configs.put(configId, authMgmtResource.getAuthenticatorConfig(exec.getId(), configId)); configs.put(configId, authMgmtResource.getAuthenticatorConfig(configId));
} }
} }
result.add(new FlowExecutions(flow, executionReps)); result.add(new FlowExecutions(flow, executionReps));

View file

@ -17,8 +17,11 @@
package org.keycloak.testsuite.admin.authentication; package org.keycloak.testsuite.admin.authentication;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.testsuite.Assert;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -28,6 +31,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.NotFoundException;
/** /**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/ */
@ -80,6 +85,41 @@ public class ProvidersTest extends AbstractAuthenticationTest {
compareProviders(expected, result); compareProviders(expected, result);
} }
@Test
public void testPerClientConfigDescriptions() {
Map<String, List<ConfigPropertyRepresentation>> configs = authMgmtResource.getPerClientConfigDescription();
Assert.assertTrue(configs.containsKey("client-jwt"));
Assert.assertTrue(configs.containsKey("client-secret"));
Assert.assertTrue(configs.containsKey("testsuite-client-passthrough"));
Assert.assertTrue(configs.get("client-jwt").isEmpty());
Assert.assertTrue(configs.get("client-secret").isEmpty());
List<ConfigPropertyRepresentation> cfg = configs.get("testsuite-client-passthrough");
Assert.assertProviderConfigProperty(cfg.get(0), "passthroughauth.foo", "Foo Property", null,
"Foo Property of this authenticator, which does nothing", "String");
Assert.assertProviderConfigProperty(cfg.get(1), "passthroughauth.bar", "Bar Property", null,
"Bar Property of this authenticator, which does nothing", "boolean");
}
@Test
public void testAuthenticatorConfigDescription() {
// Try some not-existent provider
try {
authMgmtResource.getAuthenticatorConfigDescription("not-existent");
Assert.fail("Don't expected to find provider 'not-existent'");
} catch (NotFoundException nfe) {
// Expected
}
AuthenticatorConfigInfoRepresentation infoRep = authMgmtResource.getAuthenticatorConfigDescription(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
Assert.assertEquals("Create User If Unique", infoRep.getName());
Assert.assertEquals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, infoRep.getProviderId());
Assert.assertEquals("Detect if there is existing Keycloak account with same email like identity provider. If no, create new user", infoRep.getHelpText());
Assert.assertEquals(1, infoRep.getProperties().size());
Assert.assertProviderConfigProperty(infoRep.getProperties().get(0), "require.password.update.after.registration", "Require Password Update After Registration",
null, "If this option is true and new user is successfully imported from Identity Provider to Keycloak (there is no duplicated email or username detected in Keycloak DB), then this user is required to update his password",
"boolean");
}
@Test @Test
public void testInitialAuthenticationProviders() { public void testInitialAuthenticationProviders() {

View file

@ -20,6 +20,8 @@ package org.keycloak.testsuite.admin.authentication;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation; import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
import org.keycloak.testsuite.actions.DummyRequiredActionFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -28,6 +30,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.NotFoundException;
/** /**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/ */
@ -63,6 +67,58 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
compareRequiredAction(forUpdate, 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);
// 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);
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);
}
private RequiredActionProviderRepresentation findRequiredActionByAlias(String alias, List<RequiredActionProviderRepresentation> list) { private RequiredActionProviderRepresentation findRequiredActionByAlias(String alias, List<RequiredActionProviderRepresentation> list) {
for (RequiredActionProviderRepresentation a: list) { for (RequiredActionProviderRepresentation a: list) {

View file

@ -21,7 +21,8 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation; import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import javax.ws.rs.core.GenericType; import javax.ws.rs.NotFoundException;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -50,6 +51,14 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
AuthenticationExecutionInfoRepresentation last = executions.get(executions.size() - 1); AuthenticationExecutionInfoRepresentation last = executions.get(executions.size() - 1);
AuthenticationExecutionInfoRepresentation oneButLast = executions.get(executions.size() - 2); AuthenticationExecutionInfoRepresentation oneButLast = executions.get(executions.size() - 2);
// Not possible to raisePriority of not-existent flow
try {
authMgmtResource.raisePriority("not-existent");
Assert.fail("Not expected to raise priority of not existent flow");
} catch (NotFoundException nfe) {
// Expected
}
// shift last execution up // shift last execution up
authMgmtResource.raisePriority(last.getId()); authMgmtResource.raisePriority(last.getId());
@ -61,6 +70,14 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
Assert.assertEquals("Execution shifted up - N", last.getId(), oneButLast2.getId()); Assert.assertEquals("Execution shifted up - N", last.getId(), oneButLast2.getId());
Assert.assertEquals("Execution shifted up - N-1", oneButLast.getId(), last2.getId()); Assert.assertEquals("Execution shifted up - N-1", oneButLast.getId(), last2.getId());
// Not possible to lowerPriority of not-existent flow
try {
authMgmtResource.lowerPriority("not-existent");
Assert.fail("Not expected to raise priority of not existent flow");
} catch (NotFoundException nfe) {
// Expected
}
// shift one before last down // shift one before last down
authMgmtResource.lowerPriority(oneButLast2.getId()); authMgmtResource.lowerPriority(oneButLast2.getId());
@ -72,4 +89,29 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
Assert.assertEquals("Execution shifted down - N", last.getId(), last2.getId()); Assert.assertEquals("Execution shifted down - N", last.getId(), last2.getId());
Assert.assertEquals("Execution shifted down - N-1", oneButLast.getId(), oneButLast2.getId()); Assert.assertEquals("Execution shifted down - N-1", oneButLast.getId(), oneButLast2.getId());
} }
@Test
public void testBuiltinShiftNotAllowed() {
List<AuthenticationExecutionInfoRepresentation> executions = authMgmtResource.getExecutions("browser");
AuthenticationExecutionInfoRepresentation last = executions.get(executions.size() - 1);
AuthenticationExecutionInfoRepresentation oneButLast = executions.get(executions.size() - 2);
// Not possible to raise - It's builtin flow
try {
authMgmtResource.raisePriority(last.getId());
Assert.fail("Not expected to raise priority of builtin flow");
} catch (BadRequestException nfe) {
// Expected
}
// Not possible to lower - It's builtin flow
try {
authMgmtResource.lowerPriority(oneButLast.getId());
Assert.fail("Not expected to lower priority of builtin flow");
} catch (BadRequestException nfe) {
// Expected
}
}
} }