Enable verify-profile required action by default
Closes #25985 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
f83756b177
commit
01be4032d8
13 changed files with 171 additions and 26 deletions
|
@ -12,6 +12,9 @@
|
|||
"users": [
|
||||
{
|
||||
"username": "jdoe",
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"email": "jdoe@keycloak.org",
|
||||
"enabled": true,
|
||||
"realmRoles": [],
|
||||
"clientRoles": {
|
||||
|
|
|
@ -10,6 +10,98 @@
|
|||
"attributes": {
|
||||
"userProfileEnabled": "true"
|
||||
},
|
||||
"requiredActions": [
|
||||
{
|
||||
"alias": "CONFIGURE_TOTP",
|
||||
"name": "Configure OTP",
|
||||
"providerId": "CONFIGURE_TOTP",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 10,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "TERMS_AND_CONDITIONS",
|
||||
"name": "Terms and Conditions",
|
||||
"providerId": "TERMS_AND_CONDITIONS",
|
||||
"enabled": false,
|
||||
"defaultAction": false,
|
||||
"priority": 20,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "UPDATE_PASSWORD",
|
||||
"name": "Update Password",
|
||||
"providerId": "UPDATE_PASSWORD",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 30,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "UPDATE_PROFILE",
|
||||
"name": "Update Profile",
|
||||
"providerId": "UPDATE_PROFILE",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 40,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "VERIFY_EMAIL",
|
||||
"name": "Verify Email",
|
||||
"providerId": "VERIFY_EMAIL",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 50,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "delete_account",
|
||||
"name": "Delete Account",
|
||||
"providerId": "delete_account",
|
||||
"enabled": false,
|
||||
"defaultAction": false,
|
||||
"priority": 60,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "webauthn-register",
|
||||
"name": "Webauthn Register",
|
||||
"providerId": "webauthn-register",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 70,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "webauthn-register-passwordless",
|
||||
"name": "Webauthn Register Passwordless",
|
||||
"providerId": "webauthn-register-passwordless",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 80,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "VERIFY_PROFILE",
|
||||
"name": "Verify Profile",
|
||||
"providerId": "VERIFY_PROFILE",
|
||||
"enabled": false,
|
||||
"defaultAction": false,
|
||||
"priority": 90,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"alias": "update_user_locale",
|
||||
"name": "Update User Locale",
|
||||
"providerId": "update_user_locale",
|
||||
"enabled": true,
|
||||
"defaultAction": false,
|
||||
"priority": 1000,
|
||||
"config": {}
|
||||
}
|
||||
],
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "security-admin-console-v2",
|
||||
|
|
|
@ -81,7 +81,8 @@ public class DefaultRequiredActions {
|
|||
UPDATE_EMAIL(UserModel.RequiredAction.UPDATE_EMAIL.name(), DefaultRequiredActions::addUpdateEmailAction, () -> isFeatureEnabled(Profile.Feature.UPDATE_EMAIL)),
|
||||
CONFIGURE_RECOVERY_AUTHN_CODES(UserModel.RequiredAction.CONFIGURE_RECOVERY_AUTHN_CODES.name(), DefaultRequiredActions::addRecoveryAuthnCodesAction, () -> isFeatureEnabled(Profile.Feature.RECOVERY_CODES)),
|
||||
WEBAUTHN_REGISTER("webauthn-register", DefaultRequiredActions::addWebAuthnRegisterAction, () -> isFeatureEnabled(Profile.Feature.WEB_AUTHN)),
|
||||
WEBAUTHN_PASSWORDLESS_REGISTER("webauthn-register-passwordless", DefaultRequiredActions::addWebAuthnPasswordlessRegisterAction, () -> isFeatureEnabled(Profile.Feature.WEB_AUTHN));
|
||||
WEBAUTHN_PASSWORDLESS_REGISTER("webauthn-register-passwordless", DefaultRequiredActions::addWebAuthnPasswordlessRegisterAction, () -> isFeatureEnabled(Profile.Feature.WEB_AUTHN)),
|
||||
VERIFY_USER_PROFILE(UserModel.RequiredAction.VERIFY_PROFILE.name(), DefaultRequiredActions::addVerifyProfile);
|
||||
|
||||
private final String alias;
|
||||
private final Consumer<RealmModel> addAction;
|
||||
|
@ -182,6 +183,19 @@ public class DefaultRequiredActions {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addVerifyProfile(RealmModel realm) {
|
||||
if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.VERIFY_PROFILE.name()) == null) {
|
||||
RequiredActionProviderModel termsAndConditions = new RequiredActionProviderModel();
|
||||
termsAndConditions.setEnabled(true);
|
||||
termsAndConditions.setAlias(UserModel.RequiredAction.VERIFY_PROFILE.name());
|
||||
termsAndConditions.setName("Verify Profile");
|
||||
termsAndConditions.setProviderId(UserModel.RequiredAction.VERIFY_PROFILE.name());
|
||||
termsAndConditions.setDefaultAction(false);
|
||||
termsAndConditions.setPriority(90);
|
||||
realm.addRequiredActionProvider(termsAndConditions);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addDeleteAccountAction(RealmModel realm) {
|
||||
if (realm.getRequiredActionProviderByAlias("delete_account") == null) {
|
||||
RequiredActionProviderModel deleteAccount = new RequiredActionProviderModel();
|
||||
|
|
|
@ -28,7 +28,10 @@ import org.keycloak.models.UserCredentialModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.DefaultKeyProviders;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPAttribute;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -89,6 +92,17 @@ public class ApplianceBootstrap {
|
|||
session.getContext().setRealm(realm);
|
||||
DefaultKeyProviders.createProviders(realm);
|
||||
|
||||
// In master realm the UP config is more relaxed
|
||||
// firstName, lastName and email are not required (all attributes except username)
|
||||
UserProfileProvider UserProfileProvider = session.getProvider(UserProfileProvider.class);
|
||||
UPConfig upConfig = UserProfileProvider.getConfiguration();
|
||||
for (UPAttribute attr : upConfig.getAttributes()) {
|
||||
if (!UserModel.USERNAME.equals(attr.getName())) {
|
||||
attr.setRequired(null);
|
||||
}
|
||||
}
|
||||
UserProfileProvider.setConfiguration(upConfig);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -318,10 +318,7 @@ public class KeycloakApplication extends Application {
|
|||
if (users.getUserByUsername(realm, userRep.getUsername()) != null) {
|
||||
ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername());
|
||||
} else {
|
||||
UserModel user = users.addUser(realm, userRep.getUsername());
|
||||
user.setEnabled(userRep.isEnabled());
|
||||
RepresentationToModel.createCredentials(userRep, session, realm, user, false);
|
||||
RepresentationToModel.createRoleMappings(userRep, user, realm);
|
||||
UserModel user = RepresentationToModel.createUser(session, realm, userRep);
|
||||
ServicesLogger.LOGGER.addUserSuccess(userRep.getUsername(), realmRep.getRealm());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.keycloak.admin.client.resource.UserResource;
|
|||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.cache.UserCache;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
|
@ -79,7 +78,6 @@ import java.util.Calendar;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
@ -93,6 +91,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.keycloak.models.UserModel;
|
||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST;
|
||||
|
@ -473,6 +472,10 @@ public abstract class AbstractKeycloakTest {
|
|||
assertThat(adminClient.realms().findAll().size(), is(equalTo(1)));
|
||||
}
|
||||
|
||||
protected boolean removeVerifyProfileAtImport() {
|
||||
// remove verify profile by default because most tests are not prepared
|
||||
return true;
|
||||
}
|
||||
|
||||
public void importRealm(RealmRepresentation realm) {
|
||||
if (modifyRealmForSSL()) {
|
||||
|
@ -511,6 +514,19 @@ public abstract class AbstractKeycloakTest {
|
|||
// expected when realm does not exist
|
||||
}
|
||||
adminClient.realms().create(realm);
|
||||
|
||||
if (removeVerifyProfileAtImport()) {
|
||||
try {
|
||||
RequiredActionProviderRepresentation vpModel = adminClient.realm(realm.getRealm()).flows()
|
||||
.getRequiredAction(UserModel.RequiredAction.VERIFY_PROFILE.name());
|
||||
vpModel.setEnabled(false);
|
||||
vpModel.setDefaultAction(false);
|
||||
adminClient.realm(realm.getRealm()).flows().updateRequiredAction(
|
||||
UserModel.RequiredAction.VERIFY_PROFILE.name(), vpModel);
|
||||
testingClient.testing().pollAdminEvent(); // remove the event
|
||||
} catch (NotFoundException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRealm(String realmName) {
|
||||
|
|
|
@ -191,7 +191,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
|
|||
RealmRepresentation permissionRealm = testContext.getTestRealmReps().stream().filter(realm -> {
|
||||
return realm.getRealm().equals(REALM_NAME);
|
||||
}).findFirst().get();
|
||||
adminClient.realms().create(permissionRealm);
|
||||
importRealm(permissionRealm);
|
||||
|
||||
removeTestUsers();
|
||||
createTestUsers();
|
||||
|
|
|
@ -40,6 +40,12 @@ import java.util.Map;
|
|||
*/
|
||||
public class RequiredActionsTest extends AbstractAuthenticationTest {
|
||||
|
||||
@Override
|
||||
protected boolean removeVerifyProfileAtImport() {
|
||||
// do not remove verify profile action for this test
|
||||
return false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredActions() {
|
||||
List<RequiredActionProviderRepresentation> result = authMgmtResource.getRequiredActions();
|
||||
|
@ -50,6 +56,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
|||
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, "VERIFY_PROFILE", "Verify Profile", true, false, null);
|
||||
addRequiredAction(expected, "delete_account", "Delete Account", false, false, null);
|
||||
addRequiredAction(expected, "update_user_locale", "Update User Locale", true, false, null);
|
||||
addRequiredAction(expected, "webauthn-register", "Webauthn Register", true, false, null);
|
||||
|
@ -84,7 +91,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
|
|||
|
||||
// Dummy RequiredAction is not registered in the realm and WebAuthn actions
|
||||
List<RequiredActionProviderSimpleRepresentation> result = authMgmtResource.getUnregisteredRequiredActions();
|
||||
Assert.assertEquals(2, result.size());
|
||||
Assert.assertEquals(1, result.size());
|
||||
RequiredActionProviderSimpleRepresentation action = result.stream().filter(
|
||||
a -> a.getProviderId().equals(DummyRequiredActionFactory.PROVIDER_ID)
|
||||
).findFirst().get();
|
||||
|
|
|
@ -366,7 +366,7 @@ public class RealmTest extends AbstractAdminTest {
|
|||
RealmRepresentation realmRep = testContext.getTestRealmReps().stream().filter((RealmRepresentation realm) -> {
|
||||
return realm.getRealm().equals(REALM_NAME);
|
||||
}).findFirst().get();
|
||||
adminClient.realms().create(realmRep);
|
||||
importRealm(realmRep);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -43,7 +43,7 @@ public class KcAdmSessionTest extends AbstractAdmCliTest {
|
|||
Assert.assertTrue(exe.stderrLines().get(exe.stderrLines().size() - 1).startsWith("Created "));
|
||||
|
||||
// create user
|
||||
exe = execute("create users --config '" + configFile.getName() + "' -r demorealm -s username=testuser -s enabled=true -i");
|
||||
exe = execute("create users --config '" + configFile.getName() + "' -r demorealm -s username=testuser -s firstName=testuser -s lastName=testuser -s email=testuser@keycloak.org -s enabled=true -i");
|
||||
|
||||
assertExitCodeAndStreamSizes(exe, 0, 1, 0);
|
||||
String userId = exe.stdoutLines().get(0);
|
||||
|
|
|
@ -868,7 +868,7 @@ public class UserStorageTest extends AbstractAuthTest {
|
|||
|
||||
// Re-create realm
|
||||
RealmRepresentation repOrig = testContext.getTestRealmReps().get(0);
|
||||
adminClient.realms().create(repOrig);
|
||||
importRealm(repOrig);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -49,7 +49,6 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.representations.idm.AdminEventRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPAttribute;
|
||||
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
|
||||
|
@ -113,6 +112,12 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
private static ClientRepresentation client_scope_default;
|
||||
private static ClientRepresentation client_scope_optional;
|
||||
|
||||
@Override
|
||||
protected boolean removeVerifyProfileAtImport() {
|
||||
// we need the verify profile action enabled as default
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
UserRepresentation user = UserBuilder.create().id(UUID.randomUUID().toString()).username("login-test").email("login@test.com").enabled(true).password("password").build();
|
||||
|
@ -125,17 +130,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
RealmBuilder.edit(testRealm).user(user).user(user2).user(user3).user(user4).user(user5).user(user6).user(userWithoutEmail);
|
||||
|
||||
RequiredActionProviderRepresentation action = new RequiredActionProviderRepresentation();
|
||||
action.setAlias(UserModel.RequiredAction.VERIFY_PROFILE.name());
|
||||
action.setProviderId(UserModel.RequiredAction.VERIFY_PROFILE.name());
|
||||
action.setEnabled(true);
|
||||
action.setDefaultAction(false);
|
||||
action.setPriority(10);
|
||||
|
||||
List<RequiredActionProviderRepresentation> actions = new ArrayList<>();
|
||||
actions.add(action);
|
||||
testRealm.setRequiredActions(actions);
|
||||
|
||||
testRealm.setClientScopes(new ArrayList<>());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name(SCOPE_DEPARTMENT).protocol("openid-connect").build());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("profile").protocol("openid-connect").build());
|
||||
|
|
|
@ -364,9 +364,17 @@ public class RefreshTokenTest extends AbstractKeycloakTest {
|
|||
.build());
|
||||
|
||||
realmResource.users()
|
||||
.create(UserBuilder.create().username("alice").password("alice").addRoles("offline_access").build());
|
||||
.create(UserBuilder.create().username("alice")
|
||||
.firstName("alice")
|
||||
.lastName("alice")
|
||||
.email("alice@keycloak.org")
|
||||
.password("alice").addRoles("offline_access").build());
|
||||
realmResource.users()
|
||||
.create(UserBuilder.create().username("bob").password("bob").addRoles("offline_access").build());
|
||||
.create(UserBuilder.create().username("bob")
|
||||
.firstName("bob")
|
||||
.lastName("bob")
|
||||
.email("bob@keycloak.org")
|
||||
.password("bob").addRoles("offline_access").build());
|
||||
|
||||
oauth.realm(realmName);
|
||||
oauth.clientId("public-client");
|
||||
|
|
Loading…
Reference in a new issue