Possibility to email being not required
closes #26552 Signed-off-by: mposolda <mposolda@gmail.com> Co-authored-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
b41e2f82c4
commit
10ba70c972
5 changed files with 135 additions and 14 deletions
|
@ -243,6 +243,10 @@ export const AttributeGeneralSettings = () => {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{attributeName !== "username" && (
|
||||||
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={t("required")}
|
label={t("required")}
|
||||||
|
|
|
@ -358,21 +358,22 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UserModel.EMAIL.equals(attributeName)) {
|
if (UserModel.EMAIL.equals(attributeName)) {
|
||||||
if (context.isAdminContext()) {
|
Predicate<AttributeContext> requiredFromConfig = required;
|
||||||
required = new Predicate<AttributeContext>() {
|
required = new Predicate<AttributeContext>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean test(AttributeContext context) {
|
public boolean test(AttributeContext context) {
|
||||||
UserModel user = context.getUser();
|
UserModel user = context.getUser();
|
||||||
|
|
||||||
if (user != null && user.getServiceAccountClientLink() != null) {
|
if (user != null && user.getServiceAccountClientLink() != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
RealmModel realm = context.getSession().getContext().getRealm();
|
|
||||||
return realm.isRegistrationEmailAsUsername();
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
if (requiredFromConfig.test(context)) return true;
|
||||||
|
|
||||||
|
RealmModel realm = context.getSession().getContext().getRealm();
|
||||||
|
return realm.isRegistrationEmailAsUsername();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AttributeMetadata> existingMetadata = decoratedMetadata.getAttribute(attributeName);
|
List<AttributeMetadata> existingMetadata = decoratedMetadata.getAttribute(attributeName);
|
||||||
|
|
|
@ -53,7 +53,8 @@ public class ModelTestExecutor extends LocalTestExecuter {
|
||||||
// Model test - wrap the call inside the
|
// Model test - wrap the call inside the
|
||||||
TestContext ctx = testContext.get();
|
TestContext ctx = testContext.get();
|
||||||
KeycloakTestingClient testingClient = ctx.getTestingClient();
|
KeycloakTestingClient testingClient = ctx.getTestingClient();
|
||||||
testingClient.server().runModelTest(testMethod.getDeclaringClass().getName(), testMethod.getName());
|
String realmName = annotation.realmName();
|
||||||
|
testingClient.server(realmName).runModelTest(testMethod.getDeclaringClass().getName(), testMethod.getName());
|
||||||
|
|
||||||
result.setStatus(TestResult.Status.PASSED);
|
result.setStatus(TestResult.Status.PASSED);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|
|
@ -33,4 +33,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Target({ElementType.METHOD}) // TODO: Maybe ElementClass.TYPE too? That way it will be possible to add the annotation on the the test class and not need to add on all the test methods inside the class
|
@Target({ElementType.METHOD}) // TODO: Maybe ElementClass.TYPE too? That way it will be possible to add the annotation on the the test class and not need to add on all the test methods inside the class
|
||||||
public @interface ModelTest {
|
public @interface ModelTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the realm to be set on the KeycloakContext when the test is executed. Defaults to "master" for backwards compatibility
|
||||||
|
*/
|
||||||
|
String realmName() default "master";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1257,6 +1257,116 @@ public class UserProfileTest extends AbstractUserProfileTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@ModelTest(realmName=TEST_REALM_NAME)
|
||||||
|
public void testEmailRequired(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.getContext().getRealm();
|
||||||
|
|
||||||
|
Map<String, Object> attributes = new HashMap<>();
|
||||||
|
attributes.put(UserModel.USERNAME, "james");
|
||||||
|
attributes.put(UserModel.FIRST_NAME, "James");
|
||||||
|
attributes.put(UserModel.LAST_NAME, "Doe");
|
||||||
|
UserProfile profile;
|
||||||
|
|
||||||
|
// Email required for users by default, but not for admins
|
||||||
|
UserProfileProvider provider = getUserProfileProvider(session);
|
||||||
|
UPConfig config = parseDefaultConfig();
|
||||||
|
provider.setConfiguration(config);
|
||||||
|
UPAttribute emailOrigConfig = config.getAttribute(UserModel.EMAIL);
|
||||||
|
Assert.assertEquals(emailOrigConfig.getRequired().getRoles(), Set.of(ROLE_USER)); // Should be required only for users by default
|
||||||
|
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for users");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
profile.validate();
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
Assert.fail("Should not be here as email is NOT required for administrators");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test email required in config, registrationEmailAsUsername = false : Email should be required
|
||||||
|
config.addOrReplaceAttribute(new UPAttribute(UserModel.EMAIL, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_ADMIN, ROLE_USER), Set.of())));
|
||||||
|
provider.setConfiguration(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for users");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for administrators");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test email required in config, registrationEmailAsUsername = true : Email should be required
|
||||||
|
try {
|
||||||
|
realm.setRegistrationEmailAsUsername(true);
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for users");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for administrators");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test email NOT required in config, registrationEmailAsUsername = true : Email should be required
|
||||||
|
config.addOrReplaceAttribute(new UPAttribute(UserModel.EMAIL, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)), null));
|
||||||
|
provider.setConfiguration(config);
|
||||||
|
try {
|
||||||
|
realm.setRegistrationEmailAsUsername(true);
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for users");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
profile.validate();
|
||||||
|
Assert.fail("Should not be here as email is required for administrators");
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test email NOT required in config, registrationEmailAsUsername = false : Email should NOT be required
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
|
||||||
|
profile.validate();
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
Assert.fail("Should not be here as email is required for users");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
profile.validate();
|
||||||
|
} catch (ValidationException ve) {
|
||||||
|
Assert.fail("Should not be here as email is required for administrators");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoValidationsIfUserReadOnly() {
|
public void testNoValidationsIfUserReadOnly() {
|
||||||
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfUserReadOnly);
|
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfUserReadOnly);
|
||||||
|
|
Loading…
Reference in a new issue