KEYCLOAK-12870 - Allow to pick arbitrary user for IdP linking (#6828)
* KEYCLOAK-12870 - Allow to pick arbitrary user for IdP linking * KEYCLOAK-12870: always allow to choose user if password reset is called from first broker login flow * KEYCLOAK-12870: remove "already authenticated as different user" check and message * KEYCLOAK-12870: translations * KEYCLOAK-12870: fix tests
This commit is contained in:
parent
2eab44d3f3
commit
3b24465141
35 changed files with 328 additions and 73 deletions
|
@ -40,6 +40,8 @@ public interface LoginFormsProvider extends Provider {
|
|||
|
||||
String USERNAME_EDIT_DISABLED = "usernameEditDisabled";
|
||||
|
||||
String REGISTRATION_DISABLED = "registrationDisabled";
|
||||
|
||||
|
||||
/**
|
||||
* Adds a script to the html header
|
||||
|
|
|
@ -84,14 +84,6 @@ public class ResetCredentialsActionTokenHandler extends AbstractActionTokenHande
|
|||
if (firstBrokerLoginInProgress) {
|
||||
|
||||
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession);
|
||||
if (!linkingUser.getId().equals(authenticationSession.getAuthenticatedUser().getId())) {
|
||||
return ErrorPage.error(session, authenticationSession, Response.Status.INTERNAL_SERVER_ERROR,
|
||||
Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE,
|
||||
authenticationSession.getAuthenticatedUser().getUsername(),
|
||||
linkingUser.getUsername()
|
||||
);
|
||||
}
|
||||
|
||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
authenticationSession.setAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS, serializedCtx.getIdentityProviderId());
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ public abstract class AbstractIdpAuthenticator implements Authenticator {
|
|||
// Set after firstBrokerLogin is successfully finished and contains the providerId of the provider, whose 'first-broker-login' flow was just finished
|
||||
public static final String FIRST_BROKER_LOGIN_SUCCESS = "FIRST_BROKER_LOGIN_SUCCESS";
|
||||
|
||||
// Set if nested firstBrokerLogin is detected, allowing to report a detailed error
|
||||
public static final String NESTED_FIRST_BROKER_CONTEXT = "NESTED_FIRST_BROKER_CONTEXT";
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticationFlowContext context) {
|
||||
|
|
|
@ -22,16 +22,22 @@ import org.keycloak.authentication.AuthenticationFlowError;
|
|||
import org.keycloak.authentication.AuthenticationFlowException;
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
import org.keycloak.authentication.authenticators.browser.UsernamePasswordForm;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.forms.login.LoginFormsProvider;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Same like classic username+password form, but username is "known" and user can't change it
|
||||
* Same like classic username+password form, but for use in IdP linking.
|
||||
*
|
||||
* User identity is optionally established by the preceding idp-create-user-if-unique execution.
|
||||
* In this case username field will be pre-filled (but still changeable).
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
|
@ -39,34 +45,53 @@ public class IdpUsernamePasswordForm extends UsernamePasswordForm {
|
|||
|
||||
@Override
|
||||
protected Response challenge(AuthenticationFlowContext context, MultivaluedMap<String, String> formData) {
|
||||
UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
|
||||
|
||||
return setupForm(context, formData, existingUser)
|
||||
return setupForm(context, formData, getExistingUser(context))
|
||||
.setStatus(Response.Status.OK)
|
||||
.createLoginUsernamePassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateForm(AuthenticationFlowContext context, MultivaluedMap<String, String> formData) {
|
||||
UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
|
||||
context.setUser(existingUser);
|
||||
Optional<UserModel> existingUser = getExistingUser(context);
|
||||
existingUser.ifPresent(context::setUser);
|
||||
|
||||
boolean result = validateUserAndPassword(context, formData);
|
||||
|
||||
// Restore formData for the case of error
|
||||
setupForm(context, formData, existingUser);
|
||||
|
||||
return validatePassword(context, existingUser, formData);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected LoginFormsProvider setupForm(AuthenticationFlowContext context, MultivaluedMap<String, String> formData, UserModel existingUser) {
|
||||
protected LoginFormsProvider setupForm(AuthenticationFlowContext context, MultivaluedMap<String, String> formData, Optional<UserModel> existingUser) {
|
||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(context.getAuthenticationSession(), AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
if (serializedCtx == null) {
|
||||
throw new AuthenticationFlowException("Not found serialized context in clientSession", AuthenticationFlowError.IDENTITY_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
formData.putSingle(AuthenticationManager.FORM_USERNAME, existingUser.getUsername());
|
||||
return context.form()
|
||||
existingUser.ifPresent(u -> formData.putSingle(AuthenticationManager.FORM_USERNAME, u.getUsername()));
|
||||
|
||||
LoginFormsProvider form = context.form()
|
||||
.setFormData(formData)
|
||||
.setAttribute(LoginFormsProvider.USERNAME_EDIT_DISABLED, true)
|
||||
.setInfo(Messages.FEDERATED_IDENTITY_CONFIRM_REAUTHENTICATE_MESSAGE, existingUser.getUsername(), serializedCtx.getIdentityProviderId());
|
||||
.setAttribute(LoginFormsProvider.REGISTRATION_DISABLED, true)
|
||||
.setInfo(Messages.FEDERATED_IDENTITY_CONFIRM_REAUTHENTICATE_MESSAGE, serializedCtx.getIdentityProviderId());
|
||||
|
||||
SerializedBrokeredIdentityContext serializedCtx0 = SerializedBrokeredIdentityContext.readFromAuthenticationSession(context.getAuthenticationSession(), AbstractIdpAuthenticator.NESTED_FIRST_BROKER_CONTEXT);
|
||||
if (serializedCtx0 != null) {
|
||||
BrokeredIdentityContext ctx0 = serializedCtx0.deserialize(context.getSession(), context.getAuthenticationSession());
|
||||
form.setError(Messages.NESTED_FIRST_BROKER_FLOW_MESSAGE, ctx0.getIdpConfig().getAlias(), ctx0.getUsername());
|
||||
context.getAuthenticationSession().setAuthNote(AbstractIdpAuthenticator.NESTED_FIRST_BROKER_CONTEXT, null);
|
||||
}
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
private Optional<UserModel> getExistingUser(AuthenticationFlowContext context) {
|
||||
try {
|
||||
return Optional.of(AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession()));
|
||||
} catch (AuthenticationFlowException ex) {
|
||||
log.debug("No existing user in authSession", ex);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class IdpUsernamePasswordFormFactory extends UsernamePasswordFormFactory
|
|||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Validates a password from login form. Username is already known from identity provider authentication";
|
||||
return "Validates a password from login form. Username may be already known from identity provider authentication";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,9 +54,10 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
|
|||
if (existingUserId != null) {
|
||||
UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
|
||||
|
||||
logger.debugf("Forget-password triggered when reauthenticating user after first broker login. Skipping reset-credential-choose-user screen and using user '%s' ", existingUser.getUsername());
|
||||
logger.debugf("Forget-password triggered when reauthenticating user after first broker login. Prefilling reset-credential-choose-user screen with user '%s' ", existingUser.getUsername());
|
||||
context.setUser(existingUser);
|
||||
context.success();
|
||||
Response challenge = context.form().createPasswordReset();
|
||||
context.challenge(challenge);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -400,7 +400,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
attributes.put("realm", new RealmBean(realm));
|
||||
|
||||
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
|
||||
identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData);
|
||||
identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData, context);
|
||||
attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCodeAndClientId));
|
||||
|
||||
attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));
|
||||
|
|
|
@ -17,19 +17,25 @@
|
|||
|
||||
package org.keycloak.forms.login.freemarker;
|
||||
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
import org.keycloak.forms.login.LoginFormsProvider;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Various util methods, so the logic is not hardcoded in freemarker beans
|
||||
|
@ -39,7 +45,7 @@ import java.util.Set;
|
|||
public class LoginFormsUtil {
|
||||
|
||||
// Display just those identityProviders on login screen, which are already linked to "known" established user
|
||||
public static List<IdentityProviderModel> filterIdentityProviders(List<IdentityProviderModel> providers, KeycloakSession session, RealmModel realm,
|
||||
public static List<IdentityProviderModel> filterIdentityProvidersByUser(List<IdentityProviderModel> providers, KeycloakSession session, RealmModel realm,
|
||||
Map<String, Object> attributes, MultivaluedMap<String, String> formData) {
|
||||
|
||||
Boolean usernameEditDisabled = (Boolean) attributes.get(LoginFormsProvider.USERNAME_EDIT_DISABLED);
|
||||
|
@ -71,4 +77,21 @@ public class LoginFormsUtil {
|
|||
return providers;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<IdentityProviderModel> filterIdentityProviders(List<IdentityProviderModel> providers, KeycloakSession session, RealmModel realm,
|
||||
Map<String, Object> attributes, MultivaluedMap<String, String> formData, AuthenticationFlowContext context) {
|
||||
|
||||
if (context != null) {
|
||||
AuthenticationSessionModel authSession = context.getAuthenticationSession();
|
||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
|
||||
if (serializedCtx != null) {
|
||||
IdentityProviderModel idp = serializedCtx.deserialize(session, authSession).getIdpConfig();
|
||||
return providers.stream()
|
||||
.filter(p -> !Objects.equals(p.getProviderId(), idp.getProviderId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public class Messages {
|
|||
|
||||
public static final String FEDERATED_IDENTITY_CONFIRM_REAUTHENTICATE_MESSAGE = "federatedIdentityConfirmReauthenticateMessage";
|
||||
|
||||
public static final String IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE = "identityProviderDifferentUserMessage";
|
||||
public static final String NESTED_FIRST_BROKER_FLOW_MESSAGE = "nestedFirstBrokerFlowMessage";
|
||||
|
||||
public static final String CONFIGURE_TOTP = "configureTotpMessage";
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.jboss.resteasy.spi.HttpRequest;
|
|||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.AuthenticationFlowException;
|
||||
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants;
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
|
@ -85,6 +86,7 @@ import org.keycloak.services.managers.BruteForceProtector;
|
|||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.account.AccountFormService;
|
||||
import org.keycloak.services.util.AuthenticationFlowURLHelper;
|
||||
import org.keycloak.services.util.BrowserHistoryHelper;
|
||||
import org.keycloak.services.util.CacheControlUtil;
|
||||
import org.keycloak.services.util.DefaultClientSessionContext;
|
||||
|
@ -103,6 +105,7 @@ import javax.ws.rs.WebApplicationException;
|
|||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
@ -553,7 +556,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
|
||||
if (federatedUser == null) {
|
||||
|
||||
logger.debugf("Federated user not found for provider '%s' and broker username '%s' . Redirecting to flow for firstBrokerLogin", providerId, context.getUsername());
|
||||
logger.debugf("Federated user not found for provider '%s' and broker username '%s'", providerId, context.getUsername());
|
||||
|
||||
String username = context.getModelUsername();
|
||||
if (username == null) {
|
||||
|
@ -568,6 +571,19 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
username = username.trim();
|
||||
context.setModelUsername(username);
|
||||
|
||||
SerializedBrokeredIdentityContext ctx0 = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
if (ctx0 != null) {
|
||||
SerializedBrokeredIdentityContext ctx1 = SerializedBrokeredIdentityContext.serialize(context);
|
||||
ctx1.saveToAuthenticationSession(authenticationSession, AbstractIdpAuthenticator.NESTED_FIRST_BROKER_CONTEXT);
|
||||
logger.warnv("Nested first broker flow detected: {0} -> {1}", ctx0.getIdentityProviderId(), ctx1.getIdentityProviderId());
|
||||
logger.debug("Resuming last execution");
|
||||
URI redirect = new AuthenticationFlowURLHelper(session, realmModel, session.getContext().getUri())
|
||||
.getLastExecutionUrl(authenticationSession);
|
||||
return Response.status(Status.FOUND).location(redirect).build();
|
||||
}
|
||||
|
||||
logger.debug("Redirecting to flow for firstBrokerLogin");
|
||||
|
||||
boolean forwardedPassiveLogin = "true".equals(authenticationSession.getAuthNote(AuthenticationProcessor.FORWARDED_PASSIVE_LOGIN));
|
||||
// Redirect to firstBrokerLogin after successful login and ensure that previous authentication state removed
|
||||
AuthenticationProcessor.resetFlow(authenticationSession, LoginActionsService.FIRST_BROKER_LOGIN_PATH);
|
||||
|
@ -796,11 +812,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
if (firstBrokerLoginInProgress) {
|
||||
logger.debugf("Reauthenticated with broker '%s' when linking user '%s' with other broker", context.getIdpConfig().getAlias(), federatedUser.getUsername());
|
||||
|
||||
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realmModel, authSession);
|
||||
if (!linkingUser.getId().equals(federatedUser.getId())) {
|
||||
return redirectToErrorPage(authSession, Response.Status.BAD_REQUEST, Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, federatedUser.getUsername(), linkingUser.getUsername());
|
||||
}
|
||||
|
||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
|
||||
authSession.setAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS, serializedCtx.getIdentityProviderId());
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ public class LoginPasswordResetPage extends LanguageComboboxAwarePage {
|
|||
@FindBy(partialLinkText = "Back to Login")
|
||||
private WebElement backToLogin;
|
||||
|
||||
public void changePassword() {
|
||||
submitButton.click();
|
||||
}
|
||||
|
||||
public void changePassword(String username) {
|
||||
usernameInput.clear();
|
||||
usernameInput.sendKeys(username);
|
||||
|
@ -62,6 +66,10 @@ public class LoginPasswordResetPage extends LanguageComboboxAwarePage {
|
|||
return emailErrorMessage != null ? emailErrorMessage.getText() : null;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return usernameInput.getAttribute("value");
|
||||
}
|
||||
|
||||
public void backToLogin() {
|
||||
backToLogin.click();
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
|||
addProviderInfo(result, "idp-review-profile", "Review Profile",
|
||||
"User reviews and updates profile data retrieved from Identity Provider in the displayed form");
|
||||
addProviderInfo(result, "idp-username-password-form", "Username Password Form for identity provider reauthentication",
|
||||
"Validates a password from login form. Username is already known from identity provider authentication");
|
||||
"Validates a password from login form. Username may be already known from identity provider authentication");
|
||||
addProviderInfo(result, "no-cookie-redirect", "Browser Redirect/Refresh", "Perform a 302 redirect to get user agent's current URI on authenticate path with an auth_session_id query parameter. This is for client's that do not support cookies.");
|
||||
addProviderInfo(result, "push-button-authenticator", "TEST: Button Login",
|
||||
"Just press the button to login.");
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.keycloak.testsuite.pages.InfoPage;
|
|||
import org.keycloak.testsuite.pages.LoginConfigTotpPage;
|
||||
import org.keycloak.testsuite.pages.LoginExpiredPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.LoginPasswordResetPage;
|
||||
import org.keycloak.testsuite.pages.LoginTotpPage;
|
||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||
import org.keycloak.testsuite.pages.ProceedPage;
|
||||
|
@ -112,6 +113,9 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
|
|||
@Page
|
||||
protected LoginConfigTotpPage totpPage;
|
||||
|
||||
@Page
|
||||
protected LoginPasswordResetPage loginPasswordResetPage;
|
||||
|
||||
@Page
|
||||
protected VerifyEmailPage verifyEmailPage;
|
||||
|
||||
|
@ -172,14 +176,19 @@ public abstract class AbstractBaseBrokerTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
|
||||
protected String createUser(String username) {
|
||||
UserRepresentation newUser = UserBuilder.create().username(username).email(USER_EMAIL).enabled(true).build();
|
||||
protected String createUser(String username, String email) {
|
||||
UserRepresentation newUser = UserBuilder.create().username(username).email(email).enabled(true).build();
|
||||
String userId = createUserWithAdminClient(adminClient.realm(bc.consumerRealmName()), newUser);
|
||||
resetUserPassword(adminClient.realm(bc.consumerRealmName()).users().get(userId), "password", false);
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
protected String createUser(String username) {
|
||||
return createUser(username, USER_EMAIL);
|
||||
}
|
||||
|
||||
|
||||
protected void assertNumFederatedIdentities(String userId, int expected) {
|
||||
assertEquals(expected, adminClient.realm(bc.consumerRealmName()).users().get(userId).getFederatedIdentity().size());
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.arquillian.graphene.page.Page;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.authentication.authenticators.broker.IdpConfirmLinkAuthenticatorFactory;
|
||||
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
|
@ -173,4 +174,11 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
|||
flows.updateAuthenticatorConfig(config.getId(), config);
|
||||
}
|
||||
}
|
||||
|
||||
static void disableExistingUser(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) {
|
||||
if (execution.getProviderId() != null && (execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID) || execution.getProviderId().equals(IdpConfirmLinkAuthenticatorFactory.PROVIDER_ID))) {
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.name());
|
||||
flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
assertEquals("Authenticate as consumer to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
|
@ -112,6 +112,143 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
assertNumFederatedIdentities(existingUser, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* KEYCLOAK-12870
|
||||
*/
|
||||
@Test
|
||||
public void testLinkAccountByReauthenticationWithUsernameAndPassword() {
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
String existingUser = createUser("consumer");
|
||||
String anotherUser = createUser("foobar", "foo@bar.baz");
|
||||
|
||||
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
|
||||
logInWithBroker(bc);
|
||||
|
||||
waitForPage(driver, "account already exists", false);
|
||||
assertTrue(idpConfirmLinkPage.isCurrent());
|
||||
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
Assert.fail("Not expected to see social button with " + bc.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.loginPage.clickRegister();
|
||||
Assert.fail("Not expected to see register link");
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
loginPage.login("foobar", "password");
|
||||
waitForAccountManagementTitle();
|
||||
accountUpdateProfilePage.assertCurrent();
|
||||
|
||||
assertNumFederatedIdentities(existingUser, 0);
|
||||
assertNumFederatedIdentities(anotherUser, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* KEYCLOAK-12870
|
||||
*/
|
||||
@Test
|
||||
public void testLinkAccountByReauthenticationNoExistingUser() {
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
updateExecutions(AbstractBrokerTest::disableExistingUser);
|
||||
String existingUser = createUser("consumer");
|
||||
|
||||
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
|
||||
logInWithBroker(bc);
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
Assert.fail("Not expected to see social button with " + bc.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.loginPage.clickRegister();
|
||||
Assert.fail("Not expected to see register link");
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
loginPage.login("consumer", "password");
|
||||
waitForAccountManagementTitle();
|
||||
accountUpdateProfilePage.assertCurrent();
|
||||
|
||||
assertNumFederatedIdentities(existingUser, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* KEYCLOAK-12870
|
||||
*/
|
||||
@Test
|
||||
public void testLinkAccountByReauthenticationResetPassword() {
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
String existingUser = createUser("consumer");
|
||||
|
||||
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
|
||||
logInWithBroker(bc);
|
||||
|
||||
waitForPage(driver, "account already exists", false);
|
||||
assertTrue(idpConfirmLinkPage.isCurrent());
|
||||
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
Assert.fail("Not expected to see social button with " + bc.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.loginPage.clickRegister();
|
||||
Assert.fail("Not expected to see register link");
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
loginPage.resetPassword();
|
||||
loginPasswordResetPage.assertCurrent();
|
||||
assertEquals("consumer", loginPasswordResetPage.getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* KEYCLOAK-12870
|
||||
*/
|
||||
@Test
|
||||
public void testLinkAccountByReauthenticationResetPasswordNoExistingUser() {
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
updateExecutions(AbstractBrokerTest::disableExistingUser);
|
||||
String existingUser = createUser("consumer");
|
||||
|
||||
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
|
||||
logInWithBroker(bc);
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
Assert.fail("Not expected to see social button with " + bc.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.loginPage.clickRegister();
|
||||
Assert.fail("Not expected to see register link");
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
loginPage.resetPassword();
|
||||
loginPasswordResetPage.assertCurrent();
|
||||
assertTrue(loginPasswordResetPage.getUsername().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testLinkAccountByReauthenticationWithPassword_browserButtons
|
||||
|
@ -163,11 +300,11 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
idpConfirmLinkPage.assertCurrent();
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
// Login screen shown. Username is prefilled and disabled. Registration link and social buttons are not shown
|
||||
// Login screen shown. Username is prefilled. Registration link and social buttons are not shown
|
||||
assertEquals("consumer", loginPage.getUsername());
|
||||
assertFalse(loginPage.isUsernameInputEnabled());
|
||||
assertTrue(loginPage.isUsernameInputEnabled());
|
||||
|
||||
assertEquals("Authenticate as consumer to link your account with " + bc.getIDPAlias(), this.loginPage.getInfoMessage());
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), this.loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
loginPage.findSocialButton(bc.getIDPAlias());
|
||||
|
@ -217,6 +354,8 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
configureSMTPServer();
|
||||
|
||||
this.loginPage.resetPassword();
|
||||
this.loginPasswordResetPage.assertCurrent();
|
||||
this.loginPasswordResetPage.changePassword();
|
||||
assertEquals("You should receive an email shortly with further instructions.", this.loginPage.getSuccessMessage());
|
||||
assertEquals(1, MailServer.getReceivedMessages().length);
|
||||
MimeMessage message = MailServer.getLastReceivedMessage();
|
||||
|
@ -268,6 +407,8 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
configureSMTPServer();
|
||||
|
||||
this.loginPage.resetPassword();
|
||||
this.loginPasswordResetPage.assertCurrent();
|
||||
this.loginPasswordResetPage.changePassword();
|
||||
assertEquals("You should receive an email shortly with further instructions.", this.loginPage.getSuccessMessage());
|
||||
assertEquals(1, MailServer.getReceivedMessages().length);
|
||||
MimeMessage message = MailServer.getLastReceivedMessage();
|
||||
|
|
|
@ -44,6 +44,7 @@ public class KcOidcBrokerConfiguration implements BrokerConfiguration {
|
|||
RealmRepresentation realm = new RealmRepresentation();
|
||||
realm.setRealm(REALM_CONS_NAME);
|
||||
realm.setEnabled(true);
|
||||
realm.setResetPasswordAllowed(true);
|
||||
|
||||
return realm;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public class KcOidcFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
|
|||
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
assertEquals("Authenticate as testuser to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
|
@ -72,6 +72,51 @@ public class KcOidcFirstBrokerLoginTest extends AbstractFirstBrokerLoginTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nested first broker flows are not allowed. The user wants to link federatedIdentity with existing account. He will try link by reauthentication
|
||||
* with different broker not linked to his account. Error message should be shown, and reauthentication should be resumed.
|
||||
*/
|
||||
@Test
|
||||
public void testNestedFirstBrokerFlow() {
|
||||
KcSamlBrokerConfiguration samlBrokerConfig = KcSamlBrokerConfiguration.INSTANCE;
|
||||
ClientRepresentation samlClient = samlBrokerConfig.createProviderClients(suiteContext).get(0);
|
||||
IdentityProviderRepresentation samlBroker = samlBrokerConfig.setUpIdentityProvider(suiteContext);
|
||||
RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName());
|
||||
|
||||
try {
|
||||
updateExecutions(AbstractBrokerTest::disableUpdateProfileOnFirstLogin);
|
||||
adminClient.realm(bc.providerRealmName()).clients().create(samlClient);
|
||||
consumerRealm.identityProviders().create(samlBroker);
|
||||
|
||||
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
|
||||
|
||||
createUser(bc.getUserLogin());
|
||||
|
||||
logInWithBroker(bc);
|
||||
|
||||
waitForPage(driver, "account already exists", false);
|
||||
assertTrue(idpConfirmLinkPage.isCurrent());
|
||||
assertEquals("User with email user@localhost.com already exists. How do you want to continue?", idpConfirmLinkPage.getMessage());
|
||||
idpConfirmLinkPage.clickLinkAccount();
|
||||
|
||||
assertEquals("Authenticate to link your account with " + bc.getIDPAlias(), loginPage.getInfoMessage());
|
||||
|
||||
try {
|
||||
this.loginPage.findSocialButton(bc.getIDPAlias());
|
||||
org.junit.Assert.fail("Not expected to see social button with " + samlBrokerConfig.getIDPAlias());
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
|
||||
log.debug("Clicking social " + samlBrokerConfig.getIDPAlias());
|
||||
loginPage.clickSocial(samlBrokerConfig.getIDPAlias());
|
||||
assertEquals(String.format("The %s user %s is not linked to any known user.", samlBrokerConfig.getIDPAlias(), samlBrokerConfig.getUserLogin()), loginPage.getError());
|
||||
|
||||
assertNumFederatedIdentities(consumerRealm.users().search(samlBrokerConfig.getUserLogin()).get(0).getId(), 0);
|
||||
} finally {
|
||||
updateExecutions(AbstractBrokerTest::setUpMissingUpdateProfileOnFirstLogin);
|
||||
removeUserByUsername(consumerRealm, "consumer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refers to in old test suite: OIDCFirstBrokerLoginTest#testMoreIdpAndBackButtonWhenLinkingAccount
|
||||
|
|
|
@ -51,6 +51,7 @@ public class KcSamlBrokerConfiguration implements BrokerConfiguration {
|
|||
|
||||
realm.setEnabled(true);
|
||||
realm.setRealm(REALM_CONS_NAME);
|
||||
realm.setResetPasswordAllowed(true);
|
||||
|
||||
return realm;
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ federatedIdentityExistsMessage=Ein Benutzer mit {0} {1} existiert bereits. Bitte
|
|||
|
||||
confirmLinkIdpTitle=Das Benutzerkonto existiert bereits.
|
||||
federatedIdentityConfirmLinkMessage=Ein Benutzer mit {0} {1} existiert bereits. Wie m\u00F6chten Sie fortfahren?
|
||||
federatedIdentityConfirmReauthenticateMessage=Als {0} anmelden um das Benutzerkonto mit {1} zu verkn\u00FCpfen
|
||||
federatedIdentityConfirmReauthenticateMessage=Anmelden um das Benutzerkonto mit {0} zu verkn\u00FCpfen
|
||||
confirmLinkIdpReviewProfile=Benutzerkonto \u00FCberpr\u00FCfen
|
||||
confirmLinkIdpContinue=Zu einem bestehenden Benutzerkonto hinzuf\u00FCgen
|
||||
|
||||
|
@ -221,7 +221,6 @@ couldNotObtainTokenMessage=Konnte kein Token vom Identity Provider erhalten.
|
|||
unexpectedErrorRetrievingTokenMessage=Unerwarteter Fehler w\u00E4hrend dem Empfang des Tokens vom Identity Provider.
|
||||
unexpectedErrorHandlingResponseMessage=Unerwarteter Fehler w\u00E4hrend der Bearbeitung der Antwort vom Identity Provider.
|
||||
identityProviderAuthenticationFailedMessage=Authentifizierung fehlgeschlagen. Authentifizierung mit dem Identity Provider nicht m\u00F6glich.
|
||||
identityProviderDifferentUserMessage=Als {0} authentifiziert, aber Authentifizierung als {1} erwartet
|
||||
couldNotSendAuthenticationRequestMessage=Konnte Authentifizierungsanfrage nicht an den Identity Provider senden.
|
||||
unexpectedErrorHandlingRequestMessage=Unerwarteter Fehler w\u00E4hrend der Bearbeitung der Anfrage an den Identity Provider.
|
||||
invalidAccessCodeMessage=Ung\u00FCltiger Access-Code.
|
||||
|
|
|
@ -175,7 +175,7 @@ federatedIdentityEmailExistsMessage=Cet utilisateur avec ce courriel existe d\u0
|
|||
|
||||
confirmLinkIdpTitle=Ce compte existe d\u00e9j\u00e0
|
||||
federatedIdentityConfirmLinkMessage=L''utilisateur {0} {1} existe d\u00e9j\u00e0. Que souhaitez-vous faire ?
|
||||
federatedIdentityConfirmReauthenticateMessage=Identifiez vous en tant que {0} afin de lier votre compte avec {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Identifiez vous afin de lier votre compte avec {0}
|
||||
confirmLinkIdpReviewProfile=V\u00e9rifiez vos informations de profil
|
||||
confirmLinkIdpContinue=Souhaitez-vous lier {0} \u00e0 votre compte existant
|
||||
|
||||
|
@ -228,7 +228,6 @@ couldNotObtainTokenMessage=Impossible de r\u00e9cup\u00e9rer le jeton du fournis
|
|||
unexpectedErrorRetrievingTokenMessage=Erreur inattendue lors de la r\u00e9cup\u00e9ration du jeton provenant du fournisseur d''identit\u00e9.
|
||||
unexpectedErrorHandlingResponseMessage=Erreur inattendue lors du traitement de la r\u00e9ponse provenant du fournisseur d''identit\u00e9.
|
||||
identityProviderAuthenticationFailedMessage=L''authentification a \u00e9chou\u00e9e. Impossible de s''authentifier avec le fournisseur d''identit\u00e9.
|
||||
identityProviderDifferentUserMessage=Authentifi\u00e9 en tant que {0}, alors que l''authentification aurait du \u00eatre {1}
|
||||
couldNotSendAuthenticationRequestMessage=Impossible d''envoyer la requ\u00eate d''authentification vers le fournisseur d''identit\u00e9.
|
||||
unexpectedErrorHandlingRequestMessage=Erreur inattendue lors du traitement de la requ\u00eate vers le fournisseur d''identit\u00e9.
|
||||
invalidAccessCodeMessage=Code d''acc\u00e8s invalide.
|
||||
|
|
|
@ -138,7 +138,7 @@ federatedIdentityExistsMessage=L''utente con {0} {1} esiste gi\u00e0. Effettua i
|
|||
|
||||
confirmLinkIdpTitle=Account gi\u00e0 esistente
|
||||
federatedIdentityConfirmLinkMessage=L''utente con {0} {1} esiste gi\u00e0. Come vuoi procedere?
|
||||
federatedIdentityConfirmReauthenticateMessage=Autenticati come {0} per associare il tuo account con {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Autenticati per associare il tuo account con {0}
|
||||
confirmLinkIdpReviewProfile=Rivedi profilo
|
||||
confirmLinkIdpContinue=Aggiungi all''account esistente
|
||||
|
||||
|
@ -191,7 +191,6 @@ couldNotObtainTokenMessage=Non posso ottenere un token dall''identity provider.
|
|||
unexpectedErrorRetrievingTokenMessage=Errore inaspettato nel recupero del token dall''identity provider.
|
||||
unexpectedErrorHandlingResponseMessage=Errore inaspettato nella gestione della risposta dall''identity provider.
|
||||
identityProviderAuthenticationFailedMessage=Autenticazione fallita. Non posso effettuare l''autenticazione con l''identity provider.
|
||||
identityProviderDifferentUserMessage=Autenticato come {0}, ma previsto per essere autenticato come {1}
|
||||
couldNotSendAuthenticationRequestMessage=Impossibile inviare la richiesta di autenticazione all''identity provider.
|
||||
unexpectedErrorHandlingRequestMessage=Errore inaspettato nella gestione della richiesta di autenticazione all''identity provider.
|
||||
invalidAccessCodeMessage=Codice di accesso non valido.
|
||||
|
|
|
@ -182,7 +182,7 @@ federatedIdentityExistsMessage={0} {1} のユーザーは既に存在します
|
|||
|
||||
confirmLinkIdpTitle=既に存在するアカウントです。
|
||||
federatedIdentityConfirmLinkMessage={0} {1} のユーザーは既に存在します。継続しますか?
|
||||
federatedIdentityConfirmReauthenticateMessage={1} でアカウントをリンクするために {0} として認証します
|
||||
#federatedIdentityConfirmReauthenticateMessage={1} でアカウントをリンクするために {0} として認証します
|
||||
confirmLinkIdpReviewProfile=プロフィールの確認
|
||||
confirmLinkIdpContinue=既存のアカウントに追加する
|
||||
|
||||
|
@ -240,7 +240,6 @@ couldNotObtainTokenMessage=アイデンティティ プロバイダーからト
|
|||
unexpectedErrorRetrievingTokenMessage=アイデンティティ プロバイダーからのトークン取得で予期せぬエラーが発生しました。
|
||||
unexpectedErrorHandlingResponseMessage=アイデンティティ プロバイダーからの応答を処理する際に予期せぬエラーが発生しました。
|
||||
identityProviderAuthenticationFailedMessage=認証に失敗しました。アイデンティティ プロバイダーを使用して認証できませんでした。
|
||||
identityProviderDifferentUserMessage={1} として認証されることを期待していましたが、{0} として認証されました
|
||||
couldNotSendAuthenticationRequestMessage=アイデンティティ プロバイダーに認証要求を送信することができませんでした。
|
||||
unexpectedErrorHandlingRequestMessage=アイデンティティ プロバイダーへの認証要求を処理する際に予期せぬエラーが発生しました。
|
||||
invalidAccessCodeMessage=無効なアクセスコードです。
|
||||
|
|
|
@ -143,7 +143,7 @@ federatedIdentityExistsMessage=Naudotojas {0} {1} jau egzistuoja. Prašome prsij
|
|||
|
||||
confirmLinkIdpTitle=Paskyra jau egzistuoja
|
||||
federatedIdentityConfirmLinkMessage=Naudotojas {0} {1} jau egzistuoja. Ar tęsti?
|
||||
federatedIdentityConfirmReauthenticateMessage=Prisijunkite prie {0} norėdami susieti paskyrą su {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Prisijunkite norėdami susieti paskyrą su {0}
|
||||
confirmLinkIdpReviewProfile=Peržiūrėti naudotojo profilio informaciją
|
||||
confirmLinkIdpContinue=Susieti su egzistuojančia paskyra
|
||||
|
||||
|
@ -194,7 +194,6 @@ couldNotObtainTokenMessage=Negaunamas prieigos raktas iš tapatybės teikėjo.
|
|||
unexpectedErrorRetrievingTokenMessage=Prieigos rakšo gavimo iš tapatybės teikėjo metu įvyko netikėta klaida.
|
||||
unexpectedErrorHandlingResponseMessage=Tapatybės teikėjo atsakymo apdorojimo metu įvyko netikėta klaida.
|
||||
identityProviderAuthenticationFailedMessage=Autentifikacijos klaida. Nepavyksta autentifikacija su tapatybės teikėju.
|
||||
identityProviderDifferentUserMessage=Autentifikuota kaip {0}, nors buvo tikimasi {1}
|
||||
couldNotSendAuthenticationRequestMessage=Tapatybės teikėjui nepavyksta nusiųsti autentifikacijos užklausos.
|
||||
unexpectedErrorHandlingRequestMessage=Užklausos tapatybės teikėjui formavimo metu įvyko netikėta klaida.
|
||||
invalidAccessCodeMessage=Neteisingas prieigos kodas.
|
||||
|
|
|
@ -182,7 +182,7 @@ federatedIdentityExistsMessage=Gebruiker met {0} {1} bestaat al. Log in met het
|
|||
|
||||
confirmLinkIdpTitle=Account bestaat al
|
||||
federatedIdentityConfirmLinkMessage=Gebruiker met {0} {1} bestaat al. Hoe wilt u doorgaan?
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticeer als {0} om uw account te koppelen {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticeer om uw account te koppelen {0}
|
||||
confirmLinkIdpReviewProfile=Nalopen profiel
|
||||
confirmLinkIdpContinue=Voeg toe aan bestaande account
|
||||
|
||||
|
@ -240,7 +240,6 @@ couldNotObtainTokenMessage=Kon geen token bemachtigen van de identity provider.
|
|||
unexpectedErrorRetrievingTokenMessage=Onverwachte fout bij het ophalen van de token van de identity provider.
|
||||
unexpectedErrorHandlingResponseMessage=Onverwachte fout bij het verwerken van de respons van de identity provider.
|
||||
identityProviderAuthenticationFailedMessage=Verificatie mislukt. Er kon niet worden geauthenticeerd met de identity provider.
|
||||
identityProviderDifferentUserMessage=U bent geauthenticeerd als {0}, maar u werd verwacht als {1} geauthenticeerd te zijn
|
||||
couldNotSendAuthenticationRequestMessage=Kan het authenticatieverzoek niet verzenden naar de identity provider.
|
||||
unexpectedErrorHandlingRequestMessage=Onverwachte fout bij het verwerken van het authenticatieverzoek naar de identity provider.
|
||||
invalidAccessCodeMessage=Ongeldige toegangscode.
|
||||
|
|
|
@ -141,7 +141,7 @@ federatedIdentityExistsMessage=Bruker med {0} {1} finnes allerede. Vennligst log
|
|||
|
||||
confirmLinkIdpTitle=Kontoen finnes allerede
|
||||
federatedIdentityConfirmLinkMessage=Bruker med {0} {1} finnes allerede. Hvordan vil du fortsette?
|
||||
federatedIdentityConfirmReauthenticateMessage=Bekreft at du er {0} for \u00E5 koble din konto med {1}
|
||||
#federatedIdentityConfirmReauthenticateMessage=Bekreft at du er {0} for \u00E5 koble din konto med {1}
|
||||
confirmLinkIdpReviewProfile=Se over og bekreft profil
|
||||
confirmLinkIdpContinue=Legg til eksisterende konto
|
||||
|
||||
|
@ -192,7 +192,6 @@ couldNotObtainTokenMessage=Klarte ikke \u00E5 innhente token fra identitetslever
|
|||
unexpectedErrorRetrievingTokenMessage=Uventet feil ved henting av token fra identitetsleverand\u00F8r.
|
||||
unexpectedErrorHandlingResponseMessage=Uventet feil ved h\u00E5ndtering av svar fra identitetsleverand\u00F8r.
|
||||
identityProviderAuthenticationFailedMessage=Autentisering feilet. Kunne ikke autentisere med identitetsleverand\u00F8r.
|
||||
identityProviderDifferentUserMessage= Autentisert som {0}, men forventet \u00E5 bli identifisert som {1}
|
||||
couldNotSendAuthenticationRequestMessage=Kunne ikke sende autentiseringsforesp\u00F8rsel til identitetsleverand\u00F8r.
|
||||
unexpectedErrorHandlingRequestMessage=Uventet feil ved h\u00E5ndtering av autentiseringsforesp\u00F8rsel til identitetsleverand\u00F8r.
|
||||
invalidAccessCodeMessage=Ugyldig tilgangskode.
|
||||
|
|
|
@ -181,7 +181,7 @@ federatedIdentityExistsMessage=Użytkownik z {0} {1} już istnieje. Zaloguj się
|
|||
|
||||
confirmLinkIdpTitle=Konto już istnieje
|
||||
federatedIdentityConfirmLinkMessage=Użytkownik z {0} {1} już istnieje. Co chcesz zrobić?
|
||||
federatedIdentityConfirmReauthenticateMessage=Uwierzytelnij się jako {0} aby połączyć swoje konto z {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Uwierzytelnij się aby połączyć swoje konto z {0}
|
||||
confirmLinkIdpReviewProfile=Przejrzyj profil
|
||||
confirmLinkIdpContinue=Dodaj do istniejącego konta
|
||||
|
||||
|
@ -239,7 +239,6 @@ couldNotObtainTokenMessage=Nie można uzyskać tokenu od dostawcy tożsamości.
|
|||
unexpectedErrorRetrievingTokenMessage=Nieoczekiwany błąd podczas pobierania tokenu od dostawcy tożsamości.
|
||||
unexpectedErrorHandlingResponseMessage=Nieoczekiwany błąd podczas obsługi odpowiedzi od dostawcy tożsamości.
|
||||
identityProviderAuthenticationFailedMessage=Uwierzytelnianie nie powiodło się. Nie można uwierzytelnić za pomocą dostawcy tożsamości.
|
||||
identityProviderDifferentUserMessage=Uwierzytelniony jako {0} a oczekuje się uwierzytelnienia jako {1}
|
||||
couldNotSendAuthenticationRequestMessage=Nie może wysyłać żądania uwierzytelniania do dostawcy tożsamości.
|
||||
unexpectedErrorHandlingRequestMessage=Nieoczekiwany błąd podczas obsługi żądania uwierzytelnienia do dostawcy tożsamości.
|
||||
invalidAccessCodeMessage=Nieprawidłowy kod dostępu.
|
||||
|
|
|
@ -197,7 +197,7 @@ federatedIdentityExistsMessage=Usu\u00E1rio com {0} {1} j\u00E1 existe. Por favo
|
|||
|
||||
confirmLinkIdpTitle=Conta j\u00E1 existente
|
||||
federatedIdentityConfirmLinkMessage=Usu\u00E1rio com {0} {1} j\u00E1 existe. Como voc\u00EA quer continuar?
|
||||
federatedIdentityConfirmReauthenticateMessage=Autenticar como {0} para vincular sua conta com {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Autenticar para vincular sua conta com {0}
|
||||
confirmLinkIdpReviewProfile=Revisar informa\u00E7\u00F5es do perfil
|
||||
confirmLinkIdpContinue=Vincular \u00E0 conta existente
|
||||
|
||||
|
@ -255,7 +255,6 @@ couldNotObtainTokenMessage=N\u00E3o foi poss\u00EDvel obter token do provedor de
|
|||
unexpectedErrorRetrievingTokenMessage=Erro inesperado ao recuperar token do provedor de identidade.
|
||||
unexpectedErrorHandlingResponseMessage=Erro inesperado ao manusear resposta do provedor de identidade.
|
||||
identityProviderAuthenticationFailedMessage=Falha na autentica\u00E7\u00E3o. N\u00E3o foi poss\u00EDvel autenticar com o provedor de identidade.
|
||||
identityProviderDifferentUserMessage=Autenticado como {0}, mas era esperado ser autenticado como {1}
|
||||
couldNotSendAuthenticationRequestMessage=N\u00E3o foi poss\u00EDvel enviar solicita\u00E7\u00E3o de autentica\u00E7\u00E3o para o provedor de identidade.
|
||||
unexpectedErrorHandlingRequestMessage=Erro inesperado ao manusear pedido de autentica\u00E7\u00E3o para provedor de identidade.
|
||||
invalidAccessCodeMessage=C\u00F3digo de acesso inv\u00E1lido.
|
||||
|
|
|
@ -143,7 +143,7 @@ federatedIdentityExistsMessage=Пользователь с {0} {1} уже сущ
|
|||
|
||||
confirmLinkIdpTitle=Учетная запись уже существует
|
||||
federatedIdentityConfirmLinkMessage=Пользователь с {0} {1} уже сущестует. Хотите продолжить?
|
||||
federatedIdentityConfirmReauthenticateMessage=Аутентифицируйтесь как {0} для того, чтобы связать Вашу учетную запись с {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Аутентифицируйтесь, чтобы связать Вашу учетную запись с {0}
|
||||
confirmLinkIdpReviewProfile=Обзор профиля
|
||||
confirmLinkIdpContinue=Добавить в существующую учетную запись
|
||||
|
||||
|
@ -195,7 +195,6 @@ couldNotObtainTokenMessage=Не удалось получить токен от
|
|||
unexpectedErrorRetrievingTokenMessage=Непредвиденная ошибка при получении токена от провайдера учетных записей.
|
||||
unexpectedErrorHandlingResponseMessage=Непредвиденная ошибка при обработке ответа от провайдера учетных записей.
|
||||
identityProviderAuthenticationFailedMessage=Аутентификация провалена. Невозможно аутентифицировать с поставщиком учетных записей.
|
||||
identityProviderDifferentUserMessage=Аутентифицирован как {0}, но ожидается, что будет аутентифицирован как {1}
|
||||
couldNotSendAuthenticationRequestMessage=Не получается выполнить запрос аутентификации к поставщику учетных записей.
|
||||
unexpectedErrorHandlingRequestMessage=Непредвиденная ошибка при обработке запроса аутентификации поставщика учетных записей.
|
||||
invalidAccessCodeMessage=Неверный код доступа.
|
||||
|
|
|
@ -166,7 +166,7 @@ federatedIdentityExistsMessage=Používateľ s {0} {1} už existuje. Ak chcete p
|
|||
|
||||
confirmLinkIdpTitle=Účet už existuje
|
||||
federatedIdentityConfirmLinkMessage=Používateľ s {0} {1} už existuje. Ako chcete pokračovať?
|
||||
federatedIdentityConfirmReauthenticateMessage=Overiť ako {0} prepojiť váš účet s {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Overiť prepojiť váš účet s {0}
|
||||
confirmLinkIdpReviewProfile=Skontrolujte profil
|
||||
confirmLinkIdpContinue=Pridať do existujúceho účtu
|
||||
|
||||
|
@ -219,7 +219,6 @@ couldNotObtainTokenMessage=Nemožno získať token od poskytovateľa identity.
|
|||
unexpectedErrorRetrievingTokenMessage=Neočakávaná chyba pri získavaní tokenu od poskytovateľa identity.
|
||||
unexpectedErrorHandlingResponseMessage=Neočakávaná chyba pri spracovaní odpovede od poskytovateľa identity.
|
||||
identityProviderAuthenticationFailedMessage=Overenie zlyhalo. Nepodarilo sa autentizovať s poskytovateľom identity.
|
||||
identityProviderDifferentUserMessage=Autentifikovaný ako {0}, ale očakáva sa, že bude autentizovaný ako {1}
|
||||
couldNotSendAuthenticationRequestMessage=Nemožno odoslať žiadosť o autentifikáciu poskytovateľovi identity.
|
||||
unexpectedErrorHandlingRequestMessage=Neočakávaná chyba pri spracovaní žiadosti o autentifikáciu poskytovateľovi identity.
|
||||
invalidAccessCodeMessage=Neplatný prístupový kód.
|
||||
|
|
|
@ -139,7 +139,7 @@ federatedIdentityExistsMessage=Användare med {0} {1} finns redan. Vänligen log
|
|||
|
||||
confirmLinkIdpTitle=Kontot finns redan
|
||||
federatedIdentityConfirmLinkMessage=Användare med {0} {1} finns redan, Hur vill du forsätta?
|
||||
federatedIdentityConfirmReauthenticateMessage=Autentisera som {0} för att länka ditt konto med {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Autentisera för att länka ditt konto med {0}
|
||||
confirmLinkIdpReviewProfile=Granska profil
|
||||
confirmLinkIdpContinue=Lägg till i existerande konto
|
||||
|
||||
|
@ -191,7 +191,6 @@ couldNotObtainTokenMessage=Kunde inte motta element från identitetsleverantör.
|
|||
unexpectedErrorRetrievingTokenMessage=Oväntat fel när element hämtas från identitetsleverantör.
|
||||
unexpectedErrorHandlingResponseMessage=Oväntat fel under hantering av svar från från identitetsleverantör.
|
||||
identityProviderAuthenticationFailedMessage=Autentiseringen misslyckades. Kunde inte autentisera med identitetsleverantör.
|
||||
identityProviderDifferentUserMessage=Autentiserad som {0}, men väntades att vara autentiserad som {1}
|
||||
couldNotSendAuthenticationRequestMessage=Kunde inte skicka autentiseringsförfrågan till identitetsleverantör.
|
||||
unexpectedErrorHandlingRequestMessage=Oväntat fel under hantering av autentiseringsförfrågan till identitetsleverantör.
|
||||
invalidAccessCodeMessage=Ogiltig tillträdeskod.
|
||||
|
|
|
@ -182,7 +182,7 @@ federatedIdentityExistsMessage={0} {1} kullan\u0131c\u0131 zaten var. Hesab\u013
|
|||
|
||||
confirmLinkIdpTitle=Bu Hesap Zaten Mevcut
|
||||
federatedIdentityConfirmLinkMessage={0} {1} kullan\u0131c\u0131 zaten var. Nas\u0131l devam etmek istersin?
|
||||
federatedIdentityConfirmReauthenticateMessage=Hesab\u0131n\u0131z\u0131 {1} ile ba\u011Flamak i\u00E7in {0} olarak do\u011Frulay\u0131n
|
||||
#federatedIdentityConfirmReauthenticateMessage=Hesab\u0131n\u0131z\u0131 {1} ile ba\u011Flamak i\u00E7in {0} olarak do\u011Frulay\u0131n
|
||||
confirmLinkIdpReviewProfile=Profili g\u00F6zden ge\u00E7ir
|
||||
confirmLinkIdpContinue=Mevcut hesaba ekle
|
||||
|
||||
|
@ -240,7 +240,6 @@ couldNotObtainTokenMessage=Kimlik sa\u011Flay\u0131c\u0131dan token al\u0131nama
|
|||
unexpectedErrorRetrievingTokenMessage=Kimlik sa\u011Flay\u0131c\u0131dan token al\u0131rken beklenmeyen bir hata olu\u015Ftu.
|
||||
unexpectedErrorHandlingResponseMessage=Kimlik sa\u011Flay\u0131c\u0131dan yan\u0131t al\u0131n\u0131rken beklenmeyen bir hata olu\u015Ftu.
|
||||
identityProviderAuthenticationFailedMessage=Kimlik do\u011Frulama ba\u015Far\u0131s\u0131z oldu. Kimlik sa\u011Flay\u0131c\u0131yla kimlik do\u011Frulamas\u0131 yap\u0131lamad\u0131.
|
||||
identityProviderDifferentUserMessage={0} olarak do\u011Fruland\u0131, ancak {1} olarak do\u011Frulanmas\u0131 bekleniyordu
|
||||
couldNotSendAuthenticationRequestMessage=Kimlik sa\u011Flay\u0131c\u0131ya kimlik do\u011Frulama iste\u011Fi g\u00F6nderilemedi.
|
||||
unexpectedErrorHandlingRequestMessage=Kimlik sa\u011Flay\u0131c\u0131ya kimlik do\u011Frulama iste\u011Fi i\u015Flenirken beklenmeyen bir hata olu\u015Ftu.
|
||||
invalidAccessCodeMessage=Ge\u00E7ersiz giri\u015F kodu.
|
||||
|
|
|
@ -143,7 +143,7 @@ federatedIdentityExistsMessage=用户 {0} {1} 已存在. 请登录账户管理
|
|||
|
||||
confirmLinkIdpTitle=账户已存在
|
||||
federatedIdentityConfirmLinkMessage=用户{0} {1} 已存在. 怎么继续?
|
||||
federatedIdentityConfirmReauthenticateMessage=以 {0} 登录来将 {1} 连接到您的账户
|
||||
#federatedIdentityConfirmReauthenticateMessage=以 {0} 登录来将 {1} 连接到您的账户
|
||||
confirmLinkIdpReviewProfile=审查您的信息
|
||||
confirmLinkIdpContinue=添加到已知账户
|
||||
|
||||
|
@ -194,7 +194,6 @@ couldNotObtainTokenMessage=未从身份提供者获得token
|
|||
unexpectedErrorRetrievingTokenMessage=从身份提供者获得Token时遇到未知错误
|
||||
unexpectedErrorHandlingResponseMessage=从身份提供者获得回复时遇到未知错误
|
||||
identityProviderAuthenticationFailedMessage=认证失败,无法通过身份提供者认证
|
||||
identityProviderDifferentUserMessage=认证为 {0}, 但期望认证为 {1}
|
||||
couldNotSendAuthenticationRequestMessage=无法向身份提供方发送认证请求
|
||||
unexpectedErrorHandlingRequestMessage=在处理发向认证提供方的请求时,出现未知错误。
|
||||
invalidAccessCodeMessage=无效的验证码
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</#if>
|
||||
</div>
|
||||
<#elseif section = "info" >
|
||||
<#if realm.password && realm.registrationAllowed && !usernameEditDisabled??>
|
||||
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
</#if>
|
||||
</div>
|
||||
<#elseif section = "info" >
|
||||
<#if realm.password && realm.registrationAllowed && !usernameEditDisabled??>
|
||||
<#if realm.password && realm.registrationAllowed && !registrationDisabled??>
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a tabindex="6" href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
|
|
|
@ -197,7 +197,8 @@ federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to
|
|||
|
||||
confirmLinkIdpTitle=Account already exists
|
||||
federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue?
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticate as {0} to link your account with {1}
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0}
|
||||
nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user.
|
||||
confirmLinkIdpReviewProfile=Review profile
|
||||
confirmLinkIdpContinue=Add to existing account
|
||||
|
||||
|
@ -255,7 +256,6 @@ couldNotObtainTokenMessage=Could not obtain token from identity provider.
|
|||
unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider.
|
||||
unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider.
|
||||
identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider.
|
||||
identityProviderDifferentUserMessage=Authenticated as {0}, but expected to be authenticated as {1}
|
||||
couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider.
|
||||
unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider.
|
||||
invalidAccessCodeMessage=Invalid access code.
|
||||
|
|
Loading…
Reference in a new issue