use of org.keycloak.representations.idm.RequiredActionProviderRepresentation in project keycloak by keycloak.
the class ResetCredentialsAlternativeFlowsTest method deviceNameOptionalForFirstOTPCredentialButRequiredForEachNextOne.
// KEYCLOAK-12168 Verify the 'Device Name' label is optional for the first OTP credential created
// (either via Account page or by registering new user), but required for each next created OTP credential
@Test
// TODO remove this (KEYCLOAK-16228)
@DisableFeature(value = Profile.Feature.ACCOUNT2, skipRestart = true)
public void deviceNameOptionalForFirstOTPCredentialButRequiredForEachNextOne() {
// Enable 'Default Action' on 'Configure OTP' RA for the 'test' realm
RequiredActionProviderRepresentation otpRequiredAction = testRealm().flows().getRequiredAction("CONFIGURE_TOTP");
otpRequiredAction.setDefaultAction(true);
testRealm().flows().updateRequiredAction("CONFIGURE_TOTP", otpRequiredAction);
try {
// Make a copy of the default Reset Credentials flow, but:
// * Without 'Send Reset Email' authenticator,
// * Without 'Reset Password' authenticator
final String newFlowAlias = "resetcred - KEYCLOAK-12168 - firstOTP - account - test";
configureResetCredentialsRemoveExecutionsAndBindTheFlow(newFlowAlias, Arrays.asList("reset-credential-email", "reset-password"));
/* Verify the 'Device Name' is optional when creating new OTP credential via the Account page */
// Login & set up the initial OTP code for the user
loginPage.open();
loginPage.login("login@test.com", "password");
accountTotpPage.open();
Assert.assertTrue(accountTotpPage.isCurrent());
String pageSource = driver.getPageSource();
// Check the One-time code label is followed by asterisk character (since always required)
final String oneTimeCodeLabelFollowedByAsterisk = "(?s)<label for=\"totp\"((?!</span>).)+((?=<span class=\"required\">\\*).)*";
Assert.assertTrue(Pattern.compile(oneTimeCodeLabelFollowedByAsterisk).matcher(pageSource).find());
// Check the Device Name label is not followed by asterisk character (since optional if no OTP credential defined yet)
final String asteriskPrecededByDeviceNameLabel = "(?s)((?<=<label for=\"userLabel\").)+.*<span class=\"required\">\\s+\\*";
Assert.assertFalse(Pattern.compile(asteriskPrecededByDeviceNameLabel).matcher(pageSource).find());
// Create OTP credential with empty label
final String emptyOtpLabel = "";
accountTotpPage.configure(totp.generateTOTP(accountTotpPage.getTotpSecret()), emptyOtpLabel);
// Get the updated Account TOTP page source post OTP credential creation
pageSource = driver.getPageSource();
// Check if OTP credential with empty label was created successfully
assertThat(driver.findElements(By.className("provider")).stream().map(WebElement::getText).collect(Collectors.toList()), Matchers.hasItem(""));
accountTotpPage.removeTotp();
// Logout
oauth.openLogout();
/* Verify the 'Device Name' is optional when creating the first OTP credential via the login config TOTP page */
// Register new user
loginPage.open();
loginPage.clickRegister();
registerPage.assertCurrent();
registerPage.register("Bruce", "Wilson", "bwilson@keycloak.org", "bwilson", "password", "password");
Assert.assertTrue(totpPage.isCurrent());
pageSource = driver.getPageSource();
// Check the One-time code label is required
Assert.assertTrue(Pattern.compile(oneTimeCodeLabelFollowedByAsterisk).matcher(pageSource).find());
// Check the Device Name label is optional
Assert.assertFalse(Pattern.compile(asteriskPrecededByDeviceNameLabel).matcher(pageSource).find());
// Create OTP credential with empty label
totpPage.configure(totp.generateTOTP(accountTotpPage.getTotpSecret()), emptyOtpLabel);
Assert.assertNull(totpPage.getAlertError());
Assert.assertNull(totpPage.getInputCodeError());
Assert.assertNull(totpPage.getInputLabelError());
// Assert user authenticated
appPage.assertCurrent();
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
accountTotpPage.open();
Assert.assertTrue(accountTotpPage.isCurrent());
// Check if OTP credential with empty label was created successfully
assertThat(driver.findElements(By.className("provider")).stream().map(WebElement::getText).collect(Collectors.toList()), Matchers.hasItem(""));
;
// Logout
oauth.openLogout();
/* Verify the 'Device Name' is required for each next OTP credential created via the login config TOTP page */
// Click "Forgot password" to define another OTP credential
loginPage.open();
loginPage.resetPassword();
// Should be on reset password page now. Provide email of previously registered user & click Submit button
Assert.assertTrue(resetPasswordPage.isCurrent());
resetPasswordPage.changePassword("bwilson@keycloak.org");
pageSource = driver.getPageSource();
// Check the One-time code label is required
Assert.assertTrue(Pattern.compile(oneTimeCodeLabelFollowedByAsterisk).matcher(pageSource).find());
// Check the Device Name label is required (since one OTP credential already defined)
final String deviceNameLabelFollowedByAsterisk = "(?s)<label for=\"userLabel\"((?!</span>).)+((?=<span class=\"required\">\\*).)*";
Assert.assertTrue(Pattern.compile(deviceNameLabelFollowedByAsterisk).matcher(pageSource).find());
// Try to create another OTP credential with empty label again. This
// should fail with error since OTP label is required in this case already
final String deviceNameLabelRequiredErrorMessage = "Please specify device name.";
totpPage.configure(totp.generateTOTP(accountTotpPage.getTotpSecret()), emptyOtpLabel);
Assert.assertTrue(totpPage.getInputLabelError().equals(deviceNameLabelRequiredErrorMessage));
// Create 2nd OTP credential with valid (non-empty) Device Name label. This should pass
final String secondOtpLabel = "My 2nd OTP device";
totpPage.configure(totp.generateTOTP(accountTotpPage.getTotpSecret()), secondOtpLabel);
Assert.assertNull(totpPage.getAlertError());
Assert.assertNull(totpPage.getInputCodeError());
Assert.assertNull(totpPage.getInputLabelError());
// Assert user authenticated
appPage.assertCurrent();
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
accountTotpPage.open();
Assert.assertTrue(accountTotpPage.isCurrent());
// Get the updated Account TOTP page source after both the OTP credentials were created
pageSource = driver.getPageSource();
// Verify 2nd OTP credential was successfully created too
Assert.assertTrue(pageSource.contains(secondOtpLabel));
// Remove both OTP credentials
accountTotpPage.removeTotp();
accountTotpPage.removeTotp();
// Logout
oauth.openLogout();
// Undo setup changes performed within the test
} finally {
revertFlows();
// Disable 'Default Action' on 'Configure OTP' RA for the 'test' realm
otpRequiredAction.setDefaultAction(false);
testRealm().flows().updateRequiredAction("CONFIGURE_TOTP", otpRequiredAction);
// Remove the within test registered 'bwilson' user
testingClient.server("test").run(session -> {
UserManager um = new UserManager(session);
UserModel user = session.users().getUserByUsername(session.getContext().getRealm(), "bwilson");
if (user != null) {
um.removeUser(session.getContext().getRealm(), user);
}
});
}
}
use of org.keycloak.representations.idm.RequiredActionProviderRepresentation in project keycloak by keycloak.
the class BrowserFlowTest method testLoginWithWithNoOTPCredentialAndNoRequiredActionProviderRegistered.
/**
* This test checks that if a REQUIRED authentication execution which has isUserSetupAllowed -> true
* has its requiredActionProvider in a not registered state, then it will not try to create the required action,
* and will instead raise an credential setup required error.
*/
@Test
@AuthServerContainerExclude(REMOTE)
public void testLoginWithWithNoOTPCredentialAndNoRequiredActionProviderRegistered() {
String newFlowAlias = "browser - copy 1";
configureBrowserFlowWithRequiredOTP(newFlowAlias);
RequiredActionProviderRepresentation otpRequiredAction = testRealm().flows().getRequiredAction("CONFIGURE_TOTP");
testRealm().flows().removeRequiredAction("CONFIGURE_TOTP");
try {
provideUsernamePassword("test-user@localhost");
// Assert that the login evaluates to an error, as all required elements to not validate to successful
errorPage.assertCurrent();
} finally {
revertFlows("browser - copy 1");
RequiredActionProviderSimpleRepresentation simpleRepresentation = new RequiredActionProviderSimpleRepresentation();
simpleRepresentation.setProviderId("CONFIGURE_TOTP");
simpleRepresentation.setName(otpRequiredAction.getName());
testRealm().flows().registerRequiredAction(simpleRepresentation);
}
}
use of org.keycloak.representations.idm.RequiredActionProviderRepresentation in project keycloak by keycloak.
the class BrowserFlowTest method testLoginWithWithNoWebAuthnCredentialAndRequiredActionProviderDisabled.
/**
* This test checks that if a REQUIRED authentication execution which has isUserSetupAllowed -> true
* has its requiredActionProvider disabled, then it will not try to create the required action,
* and will instead raise an credential setup required error.
* NOTE: webauthn currently isn't configured by default in the realm. When this changes, this test will need to be adapted
*/
@Test
@AuthServerContainerExclude(REMOTE)
public void testLoginWithWithNoWebAuthnCredentialAndRequiredActionProviderDisabled() {
String newFlowAlias = "browser - copy 1";
configureBrowserFlowWithRequiredWebAuthn(newFlowAlias);
RequiredActionProviderSimpleRepresentation requiredActionRepresentation = new RequiredActionProviderSimpleRepresentation();
requiredActionRepresentation.setName("WebAuthn Required Action");
requiredActionRepresentation.setProviderId(WebAuthnRegisterFactory.PROVIDER_ID);
testRealm().flows().registerRequiredAction(requiredActionRepresentation);
RequiredActionProviderRepresentation rapr = testRealm().flows().getRequiredAction(WebAuthnRegisterFactory.PROVIDER_ID);
rapr.setEnabled(false);
testRealm().flows().updateRequiredAction(WebAuthnRegisterFactory.PROVIDER_ID, rapr);
try {
provideUsernamePassword("test-user@localhost");
// Assert that the login evaluates to an error, as all required elements to not validate to successful
errorPage.assertCurrent();
} finally {
revertFlows("browser - copy 1");
testRealm().flows().removeRequiredAction(WebAuthnRegisterFactory.PROVIDER_ID);
}
}
use of org.keycloak.representations.idm.RequiredActionProviderRepresentation in project keycloak by keycloak.
the class AuthenticationManagementResource method toRepresentation.
public static RequiredActionProviderRepresentation toRepresentation(RequiredActionProviderModel model) {
RequiredActionProviderRepresentation rep = new RequiredActionProviderRepresentation();
rep.setAlias(model.getAlias());
rep.setProviderId(model.getProviderId());
rep.setName(model.getName());
rep.setDefaultAction(model.isDefaultAction());
rep.setPriority(model.getPriority());
rep.setEnabled(model.isEnabled());
rep.setConfig(model.getConfig());
return rep;
}
use of org.keycloak.representations.idm.RequiredActionProviderRepresentation in project keycloak by keycloak.
the class ManyUsersTest method before.
@Before
public void before() {
log.infof("Reading users after create is %s", READ_USER_AFTER_CREATE ? "ENABLED" : "DISABLED");
users = new LinkedList<>();
for (int i = 0; i < COUNT; i++) {
users.add(createUserRep("user" + i));
}
realmTimer.reset("create realm before test");
createRealm(REALM);
if (CREATE_OBJECTS) {
// Assuming default groups and required action already created
if (realmResource().getDefaultGroups().isEmpty()) {
log.infof("Creating default groups 'group1' and 'group2'.");
setDefaultGroup("group1");
setDefaultGroup("group2");
RequiredActionProviderRepresentation updatePassword = realmResource().flows().getRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
updatePassword.setDefaultAction(true);
realmResource().flows().updateRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString(), updatePassword);
}
}
refreshToken();
}
Aggregations