KEYCLOAK-2671 - FreeMarker form providers refactored for better (#4533)

extensibility
This commit is contained in:
Vlastimil Eliáš 2017-10-05 13:37:32 +02:00 committed by Stian Thorgersen
parent 25dbf1cfac
commit c9da02912e
28 changed files with 414 additions and 322 deletions

View file

@ -22,6 +22,7 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.Provider;
import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@ -74,6 +75,8 @@ public interface LoginFormsProvider extends Provider {
public Response createOAuthGrant();
public Response createCode();
public LoginFormsProvider setAuthenticationSession(AuthenticationSessionModel authenticationSession);
public LoginFormsProvider setClientSessionCode(String accessCode);

View file

@ -469,6 +469,7 @@ public class AuthenticationProcessor {
String accessCode = generateAccessCode();
URI action = getActionUrl(accessCode);
LoginFormsProvider provider = getSession().getProvider(LoginFormsProvider.class)
.setAuthenticationSession(getAuthenticationSession())
.setUser(getUser())
.setActionUri(action)
.setExecution(getExecution().getId())
@ -609,25 +610,25 @@ public class AuthenticationProcessor {
if (e.getError() == AuthenticationFlowError.INVALID_USER) {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.USER_NOT_FOUND);
return ErrorPage.error(session, Messages.INVALID_USER);
return ErrorPage.error(session, authenticationSession, Messages.INVALID_USER);
} else if (e.getError() == AuthenticationFlowError.USER_DISABLED) {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.USER_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
return ErrorPage.error(session,authenticationSession, Messages.ACCOUNT_DISABLED);
} else if (e.getError() == AuthenticationFlowError.USER_TEMPORARILY_DISABLED) {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.USER_TEMPORARILY_DISABLED);
return ErrorPage.error(session, Messages.INVALID_USER);
return ErrorPage.error(session,authenticationSession, Messages.INVALID_USER);
} else if (e.getError() == AuthenticationFlowError.INVALID_CLIENT_SESSION) {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.INVALID_CODE);
return ErrorPage.error(session, authenticationSession, Messages.INVALID_CODE);
} else if (e.getError() == AuthenticationFlowError.EXPIRED_CODE) {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.EXPIRED_CODE);
return ErrorPage.error(session, Messages.EXPIRED_CODE);
return ErrorPage.error(session, authenticationSession, Messages.EXPIRED_CODE);
} else if (e.getError() == AuthenticationFlowError.FORK_FLOW) {
ForkFlowException reset = (ForkFlowException)e;
@ -654,13 +655,13 @@ public class AuthenticationProcessor {
} else {
ServicesLogger.LOGGER.failedAuthentication(e);
event.error(Errors.INVALID_USER_CREDENTIALS);
return ErrorPage.error(session, Messages.INVALID_USER);
return ErrorPage.error(session, authenticationSession, Messages.INVALID_USER);
}
} else {
ServicesLogger.LOGGER.failedAuthentication(failure);
event.error(Errors.INVALID_USER_CREDENTIALS);
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_REQUEST);
return ErrorPage.error(session, authenticationSession, Messages.UNEXPECTED_ERROR_HANDLING_REQUEST);
}
}
@ -885,7 +886,7 @@ public class AuthenticationProcessor {
if (!authSession.getAuthenticatedUser().equals(userSession.getUser())) {
event.detail(Details.EXISTING_USER, userSession.getUser().getId());
event.error(Errors.DIFFERENT_USER_AUTHENTICATED);
throw new ErrorPageException(session, Messages.DIFFERENT_USER_AUTHENTICATED, userSession.getUser().getUsername());
throw new ErrorPageException(session, authSession, Messages.DIFFERENT_USER_AUTHENTICATED, userSession.getUser().getUsername());
}
}
userSession.setState(UserSessionModel.State.LOGGED_IN);

View file

@ -269,6 +269,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
String code = processor.generateCode();
URI actionUrl = getActionUrl(executionId, code);
LoginFormsProvider form = processor.getSession().getProvider(LoginFormsProvider.class)
.setAuthenticationSession(processor.getAuthenticationSession())
.setActionUri(actionUrl)
.setExecution(executionId)
.setClientSessionCode(code)

View file

@ -166,6 +166,7 @@ public class RequiredActionContextResult implements RequiredActionContext {
String accessCode = generateCode();
URI action = getActionUrl(accessCode);
LoginFormsProvider provider = getSession().getProvider(LoginFormsProvider.class)
.setAuthenticationSession(getAuthenticationSession())
.setUser(getUser())
.setActionUri(action)
.setExecution(getExecution())

View file

@ -80,6 +80,7 @@ public class ExecuteActionsActionTokenHandler extends AbstractActionTokenHander<
String confirmUri = builder.build(realm.getName()).toString();
return session.getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setSuccess(Messages.CONFIRM_EXECUTION_OF_ACTIONS)
.setAttribute(Constants.TEMPLATE_ATTR_ACTION_URI, confirmUri)
.setAttribute(Constants.TEMPLATE_ATTR_REQUIRED_ACTIONS, token.getRequiredActions())

View file

@ -81,6 +81,7 @@ public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenH
String confirmUri = builder.build(realm.getName()).toString();
return session.getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setSuccess(Messages.CONFIRM_ACCOUNT_LINKING, token.getIdentityProviderUsername(), token.getIdentityProviderAlias())
.setAttribute(Constants.TEMPLATE_ATTR_ACTION_URI, confirmUri)
.createInfoPage();
@ -106,6 +107,7 @@ public class IdpVerifyAccountLinkActionTokenHandler extends AbstractActionTokenH
}
return session.getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setSuccess(Messages.IDENTITY_PROVIDER_LINK_SUCCESS, token.getIdentityProviderAlias(), token.getIdentityProviderUsername())
.setAttribute(Constants.SKIP_LINK, true)
.createInfoPage();

View file

@ -85,7 +85,7 @@ public class ResetCredentialsActionTokenHandler extends AbstractActionTokenHande
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession);
if (!linkingUser.getId().equals(authenticationSession.getAuthenticatedUser().getId())) {
return ErrorPage.error(session,
return ErrorPage.error(session, authenticationSession,
Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE,
authenticationSession.getAuthenticatedUser().getUsername(),
linkingUser.getUsername()

View file

@ -82,6 +82,7 @@ public class VerifyEmailActionTokenHandler extends AbstractActionTokenHander<Ver
String confirmUri = builder.build(realm.getName()).toString();
return session.getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setSuccess(Messages.CONFIRM_EMAIL_ADDRESS_VERIFICATION, user.getEmail())
.setAttribute(Constants.TEMPLATE_ATTR_ACTION_URI, confirmUri)
.createInfoPage();
@ -99,6 +100,7 @@ public class VerifyEmailActionTokenHandler extends AbstractActionTokenHander<Ver
asm.removeAuthenticationSession(tokenContext.getRealm(), authSession, true);
return tokenContext.getSession().getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setSuccess(Messages.EMAIL_VERIFIED)
.createInfoPage();
}

View file

@ -119,6 +119,7 @@ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator imple
}
if (context.getExecution().isRequired()) {
return context.getSession().getProvider(LoginFormsProvider.class)
.setAuthenticationSession(context.getAuthenticationSession())
.setStatus(Response.Status.UNAUTHORIZED)
.setResponseHeader(HttpHeaders.WWW_AUTHENTICATE, negotiateHeader)
.setError(Messages.KERBEROS_NOT_ENABLED).createErrorPage();

View file

@ -37,7 +37,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.ErrorPage;
@ -400,7 +399,7 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
}
event.event(EventType.LOGIN);
event.error(Errors.IDENTITY_PROVIDER_LOGIN_FAILURE);
return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
return ErrorPage.error(session, null, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
}
public SimpleHttp generateTokenRequest(String authorizationCode) {

View file

@ -111,14 +111,14 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
EventBuilder event = new EventBuilder(realm, session, clientConnection);
event.event(EventType.LOGOUT);
event.error(Errors.USER_SESSION_NOT_FOUND);
return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
return ErrorPage.error(session, null, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
}
if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) {
logger.error("usersession in different state");
EventBuilder event = new EventBuilder(realm, session, clientConnection);
event.event(EventType.LOGOUT);
event.error(Errors.USER_SESSION_NOT_FOUND);
return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
return ErrorPage.error(session, null, Messages.SESSION_NOT_ACTIVE);
}
return AuthenticationManager.finishBrowserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
}

View file

@ -87,12 +87,10 @@ import java.util.List;
import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
import org.w3c.dom.Element;
import java.util.*;
import javax.xml.crypto.dsig.XMLSignature;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
/**
@ -194,18 +192,18 @@ public class SAMLEndpoint {
if (!checkSsl()) {
event.event(EventType.LOGIN);
event.error(Errors.SSL_REQUIRED);
return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
return ErrorPage.error(session, null, Messages.HTTPS_REQUIRED);
}
if (!realm.isEnabled()) {
event.event(EventType.LOGIN_ERROR);
event.error(Errors.REALM_DISABLED);
return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
return ErrorPage.error(session, null, Messages.REALM_NOT_ENABLED);
}
if (samlRequest == null && samlResponse == null) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
return null;
@ -247,7 +245,7 @@ public class SAMLEndpoint {
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
if (config.isValidateSignature()) {
try {
@ -256,7 +254,7 @@ public class SAMLEndpoint {
logger.error("validation failed", e);
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.error(Errors.INVALID_SIGNATURE);
return ErrorPage.error(session, Messages.INVALID_REQUESTER);
return ErrorPage.error(session, null, Messages.INVALID_REQUESTER);
}
}
@ -269,7 +267,7 @@ public class SAMLEndpoint {
} else {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
}
@ -342,6 +340,7 @@ public class SAMLEndpoint {
private String getEntityId(UriInfo uriInfo, RealmModel realm) {
return UriBuilder.fromUri(uriInfo.getBaseUri()).path("realms").path(realm.getName()).build().toString();
}
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState, String clientId) {
try {
@ -360,7 +359,7 @@ public class SAMLEndpoint {
logger.error("The assertion is not encrypted, which is required.");
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.error(Errors.INVALID_SAML_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_REQUESTER);
return ErrorPage.error(session, null, Messages.INVALID_REQUESTER);
}
Element assertionElement;
@ -380,7 +379,7 @@ public class SAMLEndpoint {
logger.error("validation failed");
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.error(Errors.INVALID_SIGNATURE);
return ErrorPage.error(session, Messages.INVALID_REQUESTER);
return ErrorPage.error(session, null, Messages.INVALID_REQUESTER);
}
AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
@ -464,7 +463,7 @@ public class SAMLEndpoint {
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_FEDERATED_IDENTITY_ACTION);
return ErrorPage.error(session, null, Messages.INVALID_FEDERATED_IDENTITY_ACTION);
}
if (config.isValidateSignature()) {
try {
@ -473,7 +472,7 @@ public class SAMLEndpoint {
logger.error("validation failed", e);
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
event.error(Errors.INVALID_SIGNATURE);
return ErrorPage.error(session, Messages.INVALID_FEDERATED_IDENTITY_ACTION);
return ErrorPage.error(session, null, Messages.INVALID_FEDERATED_IDENTITY_ACTION);
}
}
if (statusResponse instanceof ResponseType) {
@ -492,20 +491,20 @@ public class SAMLEndpoint {
logger.error("no valid user session");
event.event(EventType.LOGOUT);
event.error(Errors.USER_SESSION_NOT_FOUND);
return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
return ErrorPage.error(session, null, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
}
UserSessionModel userSession = session.sessions().getUserSession(realm, relayState);
if (userSession == null) {
logger.error("no valid user session");
event.event(EventType.LOGOUT);
event.error(Errors.USER_SESSION_NOT_FOUND);
return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
return ErrorPage.error(session, null, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
}
if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) {
logger.error("usersession in different state");
event.event(EventType.LOGOUT);
event.error(Errors.USER_SESSION_NOT_FOUND);
return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
return ErrorPage.error(session, null, Messages.SESSION_NOT_ACTIVE);
}
return AuthenticationManager.finishBrowserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
}

View file

@ -35,6 +35,7 @@ import org.keycloak.theme.Theme;
import org.keycloak.theme.ThemeProvider;
import org.keycloak.theme.beans.MessageFormatterMethod;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
@ -150,7 +151,6 @@ public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider {
attributes.put("realmName", getRealmName());
send("executeActionsSubject", "executeActions.ftl", attributes);
}
@Override
@ -171,8 +171,7 @@ public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider {
protected EmailTemplate processTemplate(String subjectKey, List<Object> subjectAttributes, String template, Map<String, Object> attributes) throws EmailException {
try {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme = themeProvider.getTheme(realm.getEmailTheme(), Theme.Type.EMAIL);
Theme theme = getTheme();
Locale locale = session.getContext().resolveLocale(user);
attributes.put("locale", locale);
Properties rb = theme.getMessages(locale);
@ -198,10 +197,18 @@ public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider {
throw new EmailException("Failed to template email", e);
}
}
protected Theme getTheme() throws IOException {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
return themeProvider.getTheme(realm.getEmailTheme(), Theme.Type.EMAIL);
}
protected void send(String subjectKey, List<Object> subjectAttributes, String template, Map<String, Object> attributes) throws EmailException {
try {
EmailTemplate email = processTemplate(subjectKey, subjectAttributes, template, attributes);
send(email.getSubject(), email.getTextBody(), email.getHtmlBody());
} catch (EmailException e){
throw e;
} catch (Exception e) {
throw new EmailException("Failed to template email", e);
}

View file

@ -71,26 +71,26 @@ public class FreeMarkerAccountProvider implements AccountProvider {
private static final Logger logger = Logger.getLogger(FreeMarkerAccountProvider.class);
private UserModel user;
private MultivaluedMap<String, String> profileFormData;
private Response.Status status = Response.Status.OK;
private RealmModel realm;
private String[] referrer;
private List<Event> events;
private String stateChecker;
private List<UserSessionModel> sessions;
private boolean identityProviderEnabled;
private boolean eventsEnabled;
private boolean passwordUpdateSupported;
private boolean passwordSet;
private KeycloakSession session;
private FreeMarkerUtil freeMarker;
private HttpHeaders headers;
protected UserModel user;
protected MultivaluedMap<String, String> profileFormData;
protected Response.Status status = Response.Status.OK;
protected RealmModel realm;
protected String[] referrer;
protected List<Event> events;
protected String stateChecker;
protected List<UserSessionModel> sessions;
protected boolean identityProviderEnabled;
protected boolean eventsEnabled;
protected boolean passwordUpdateSupported;
protected boolean passwordSet;
protected KeycloakSession session;
protected FreeMarkerUtil freeMarker;
protected HttpHeaders headers;
private UriInfo uriInfo;
protected UriInfo uriInfo;
private List<FormMessage> messages = null;
private MessageType messageType = MessageType.ERROR;
protected List<FormMessage> messages = null;
protected MessageType messageType = MessageType.ERROR;
public FreeMarkerAccountProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
this.session = session;
@ -112,30 +112,16 @@ public class FreeMarkerAccountProvider implements AccountProvider {
public Response createResponse(AccountPages page) {
Map<String, Object> attributes = new HashMap<String, Object>();
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme;
try {
theme = themeProvider.getTheme(realm.getAccountTheme(), Theme.Type.ACCOUNT);
theme = getTheme();
} catch (IOException e) {
logger.error("Failed to create theme", e);
return Response.serverError().build();
}
try {
attributes.put("properties", theme.getProperties());
} catch (IOException e) {
logger.warn("Failed to load properties", e);
}
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle;
try {
messagesBundle = theme.getMessages(locale);
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
} catch (IOException e) {
logger.warn("Failed to load messages", e);
messagesBundle = new Properties();
}
Properties messagesBundle = handleThemeResources(theme, locale, attributes);
URI baseUri = uriInfo.getBaseUri();
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
@ -148,19 +134,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
attributes.put("stateChecker", stateChecker);
}
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
if (messages != null) {
MessageBean wholeMessage = new MessageBean(null, messageType);
for (FormMessage message : this.messages) {
String formattedMessageText = formatMessage(message, messagesBundle, locale);
if (formattedMessageText != null) {
wholeMessage.appendSummaryLine(formattedMessageText);
messagesPerField.addMessage(message.getField(), formattedMessageText, messageType);
}
}
attributes.put("message", wholeMessage);
}
attributes.put("messagesPerField", messagesPerField);
handleMessages(locale, messagesBundle, attributes);
if (referrer != null) {
attributes.put("referrer", new ReferrerBean(referrer));
@ -173,12 +147,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
attributes.put("url", new UrlBean(realm, theme, baseUri, baseQueryUri, uriInfo.getRequestUri(), stateChecker));
if (realm.isInternationalizationEnabled()) {
UriBuilder b;
switch (page) {
default:
b = UriBuilder.fromUri(baseQueryUri).path(uriInfo.getPath());
break;
}
UriBuilder b = UriBuilder.fromUri(baseQueryUri).path(uriInfo.getPath());
attributes.put("locale", new LocaleBean(realm, locale, b, messagesBundle));
}
@ -204,8 +173,84 @@ public class FreeMarkerAccountProvider implements AccountProvider {
break;
case PASSWORD:
attributes.put("password", new PasswordBean(passwordSet));
break;
default:
}
return processTemplate(theme, page, attributes, locale);
}
/**
* Get Theme used for page rendering.
*
* @return theme for page rendering, never null
* @throws IOException in case of Theme loading problem
*/
protected Theme getTheme() throws IOException {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
return themeProvider.getTheme(realm.getAccountTheme(), Theme.Type.ACCOUNT);
}
/**
* Load message bundle and place it into <code>msg</code> template attribute. Also load Theme properties and place them into <code>properties</code> template attribute.
*
* @param theme actual Theme to load bundle from
* @param locale to load bundle for
* @param attributes template attributes to add resources to
* @return message bundle for other use
*/
protected Properties handleThemeResources(Theme theme, Locale locale, Map<String, Object> attributes) {
Properties messagesBundle;
try {
messagesBundle = theme.getMessages(locale);
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
} catch (IOException e) {
logger.warn("Failed to load messages", e);
messagesBundle = new Properties();
}
try {
attributes.put("properties", theme.getProperties());
} catch (IOException e) {
logger.warn("Failed to load properties", e);
}
return messagesBundle;
}
/**
* Handle messages to be shown on the page - set them to template attributes
*
* @param locale to be used for message text loading
* @param messagesBundle to be used for message text loading
* @param attributes template attributes to messages related info to
* @see #messageType
* @see #messages
*/
protected void handleMessages(Locale locale, Properties messagesBundle, Map<String, Object> attributes) {
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
if (messages != null) {
MessageBean wholeMessage = new MessageBean(null, messageType);
for (FormMessage message : this.messages) {
String formattedMessageText = formatMessage(message, messagesBundle, locale);
if (formattedMessageText != null) {
wholeMessage.appendSummaryLine(formattedMessageText);
messagesPerField.addMessage(message.getField(), formattedMessageText, messageType);
}
}
attributes.put("message", wholeMessage);
}
attributes.put("messagesPerField", messagesPerField);
}
/**
* Process FreeMarker template and prepare Response. Some fields are used for rendering also.
*
* @param theme to be used (provided by <code>getTheme()</code>)
* @param page to be rendered
* @param attributes pushed to the template
* @param locale to be used
* @return Response object to be returned to the browser, never null
*/
protected Response processTemplate(Theme theme, AccountPages page, Map<String, Object> attributes, Locale locale) {
try {
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8_TYPE).language(locale).entity(result);

View file

@ -39,6 +39,7 @@ import org.keycloak.models.*;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.Urls;
import org.keycloak.services.messages.Messages;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.theme.BrowserSecurityHeaderSetup;
import org.keycloak.theme.FreeMarkerException;
import org.keycloak.theme.FreeMarkerUtil;
@ -68,42 +69,52 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private static final Logger logger = Logger.getLogger(FreeMarkerLoginFormsProvider.class);
private String accessCode;
private Response.Status status;
private List<RoleModel> realmRolesRequested;
private MultivaluedMap<String, RoleModel> resourceRolesRequested;
private List<ProtocolMapperModel> protocolMappersRequested;
private Map<String, String> httpResponseHeaders = new HashMap<String, String>();
private String accessRequestMessage;
private URI actionUri;
private String execution;
protected String accessCode;
protected Response.Status status;
protected List<RoleModel> realmRolesRequested;
protected MultivaluedMap<String, RoleModel> resourceRolesRequested;
protected List<ProtocolMapperModel> protocolMappersRequested;
protected Map<String, String> httpResponseHeaders = new HashMap<String, String>();
protected String accessRequestMessage;
protected URI actionUri;
protected String execution;
private List<FormMessage> messages = null;
private MessageType messageType = MessageType.ERROR;
protected List<FormMessage> messages = null;
protected MessageType messageType = MessageType.ERROR;
private MultivaluedMap<String, String> formData;
protected MultivaluedMap<String, String> formData;
private KeycloakSession session;
private FreeMarkerUtil freeMarker;
protected KeycloakSession session;
/** authenticationSession can be null for some renderings, mainly error pages */
protected AuthenticationSessionModel authenticationSession;
protected RealmModel realm;
protected ClientModel client;
protected UriInfo uriInfo;
private UserModel user;
protected FreeMarkerUtil freeMarker;
private final Map<String, Object> attributes = new HashMap<String, Object>();
protected UserModel user;
protected final Map<String, Object> attributes = new HashMap<String, Object>();
public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
this.session = session;
this.freeMarker = freeMarker;
this.attributes.put("scripts", new LinkedList<String>());
this.realm = session.getContext().getRealm();
this.client = session.getContext().getClient();
this.uriInfo = session.getContext().getUri();
}
@SuppressWarnings("unchecked")
@Override
public void addScript(String scriptUrl) {
List<String> scripts = (List<String>)this.attributes.get("scripts");
List<String> scripts = (List<String>) this.attributes.get("scripts");
scripts.add(scriptUrl);
}
@Override
public Response createResponse(UserModel.RequiredAction action) {
RealmModel realm = session.getContext().getRealm();
String actionMessage;
LoginFormsPages page;
@ -139,110 +150,29 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return createResponse(page);
}
private Response createResponse(LoginFormsPages page) {
RealmModel realm = session.getContext().getRealm();
ClientModel client = session.getContext().getClient();
UriInfo uriInfo = session.getContext().getUri();
@SuppressWarnings("incomplete-switch")
protected Response createResponse(LoginFormsPages page) {
String requestURI = uriInfo.getBaseUri().getPath();
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
if (page == LoginFormsPages.OAUTH_GRANT) {
// for some reason Resteasy 2.3.7 doesn't like query params and form params with the same name and will null out the code form param
uriBuilder.replaceQuery(null);
if (status == null) {
status = Response.Status.OK;
}
if (client != null) {
uriBuilder.queryParam(Constants.CLIENT_ID, client.getClientId());
}
URI baseUri = uriBuilder.build();
if (accessCode != null) {
uriBuilder.queryParam(OAuth2Constants.CODE, accessCode);
}
URI baseUriWithCodeAndClientId = uriBuilder.build();
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme;
try {
theme = themeProvider.getTheme(realm.getLoginTheme(), Theme.Type.LOGIN);
theme = getTheme();
} catch (IOException e) {
logger.error("Failed to create theme", e);
return Response.serverError().build();
}
try {
attributes.put("properties", theme.getProperties());
} catch (IOException e) {
logger.warn("Failed to load properties", e);
}
Properties messagesBundle;
Locale locale = session.getContext().resolveLocale(user);
try {
messagesBundle = theme.getMessages(locale);
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
} catch (IOException e) {
logger.warn("Failed to load messages", e);
messagesBundle = new Properties();
}
Properties messagesBundle = handleThemeResources(theme, locale);
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
if (messages != null) {
MessageBean wholeMessage = new MessageBean(null, messageType);
for (FormMessage message : this.messages) {
String formattedMessageText = formatMessage(message, messagesBundle, locale);
if (formattedMessageText != null) {
wholeMessage.appendSummaryLine(formattedMessageText);
messagesPerField.addMessage(message.getField(), formattedMessageText, messageType);
}
}
attributes.put("message", wholeMessage);
} else {
attributes.put("message", null);
}
attributes.put("messagesPerField", messagesPerField);
handleMessages(locale, messagesBundle);
attributes.put("requiredActionUrl", new RequiredActionUrlFormatterMethod(realm, baseUri));
if (realm != null && user != null && session != null) {
attributes.put("authenticatorConfigured", new AuthenticatorConfiguredMethod(realm, user, session));
}
if (realm != null) {
attributes.put("realm", new RealmBean(realm));
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData);
attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCodeAndClientId));
attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));
if (realm.isInternationalizationEnabled()) {
UriBuilder b;
switch (page) {
case LOGIN:
b = UriBuilder.fromUri(Urls.realmLoginPage(baseUri, realm.getName()));
break;
case REGISTER:
b = UriBuilder.fromUri(Urls.realmRegisterPage(baseUri, realm.getName()));
break;
default:
b = UriBuilder.fromUri(baseUri).path(uriInfo.getPath());
break;
}
if (execution != null) {
b.queryParam(Constants.EXECUTION, execution);
}
attributes.put("locale", new LocaleBean(realm, locale, b, messagesBundle));
}
}
if (client != null) {
attributes.put("client", new ClientBean(client, baseUri));
}
// for some reason Resteasy 2.3.7 doesn't like query params and form params with the same name and will null out the code form param
UriBuilder uriBuilder = prepareBaseUriBuilder(page == LoginFormsPages.OAUTH_GRANT);
createCommonAttributes(theme, locale, messagesBundle, uriBuilder, page);
attributes.put("login", new LoginBean(formData));
@ -267,7 +197,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
attributes.put("register", new RegisterBean(formData));
break;
case OAUTH_GRANT:
attributes.put("oauth", new OAuthGrantBean(accessCode, client, realmRolesRequested, resourceRolesRequested, protocolMappersRequested, this.accessRequestMessage));
attributes.put("oauth",
new OAuthGrantBean(accessCode, client, realmRolesRequested, resourceRolesRequested, protocolMappersRequested, this.accessRequestMessage));
attributes.put("advancedMsg", new AdvancedMessageFormatterMethod(locale, messagesBundle));
break;
case CODE:
@ -279,62 +210,74 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
status = Response.Status.OK;
}
try {
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8).entity(result);
BrowserSecurityHeaderSetup.headers(builder, realm);
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
return builder.build();
} catch (FreeMarkerException e) {
logger.error("Failed to process template", e);
return Response.serverError().build();
}
return processTemplate(theme, Templates.getTemplate(page), locale);
}
@Override
public Response createForm(String form) {
RealmModel realm = session.getContext().getRealm();
ClientModel client = session.getContext().getClient();
UriInfo uriInfo = session.getContext().getUri();
String requestURI = uriInfo.getBaseUri().getPath();
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
if (client != null) {
uriBuilder.queryParam(Constants.CLIENT_ID, client.getClientId());
if (status == null) {
status = Response.Status.OK;
}
URI baseUri = uriBuilder.build();
if (accessCode != null) {
uriBuilder.queryParam(OAuth2Constants.CODE, accessCode);
}
URI baseUriWithCode = uriBuilder.build();
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme;
try {
theme = themeProvider.getTheme(realm.getLoginTheme(), Theme.Type.LOGIN);
theme = getTheme();
} catch (IOException e) {
logger.error("Failed to create theme", e);
return Response.serverError().build();
}
try {
attributes.put("properties", theme.getProperties());
} catch (IOException e) {
logger.warn("Failed to load properties", e);
}
if (client != null) {
attributes.put("client", new ClientBean(client, baseUri));
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle = handleThemeResources(theme, locale);
handleMessages(locale, messagesBundle);
UriBuilder uriBuilder = prepareBaseUriBuilder(false);
createCommonAttributes(theme, locale, messagesBundle, uriBuilder, null);
return processTemplate(theme, form, locale);
}
/**
* Prepare base uri builder for later use
*
* @param resetRequestUriParams - for some reason Resteasy 2.3.7 doesn't like query params and form params with the same name and will null out the code form param, so we have to reset them for some pages
* @return base uri builder
*/
protected UriBuilder prepareBaseUriBuilder(boolean resetRequestUriParams) {
String requestURI = uriInfo.getBaseUri().getPath();
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
if (resetRequestUriParams) {
uriBuilder.replaceQuery(null);
}
if (client != null) {
uriBuilder.queryParam(Constants.CLIENT_ID, client.getClientId());
}
return uriBuilder;
}
/**
* Get Theme used for page rendering.
*
* @return theme for page rendering, never null
* @throws IOException in case of Theme loading problem
*/
protected Theme getTheme() throws IOException {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
return themeProvider.getTheme(realm.getLoginTheme(), Theme.Type.LOGIN);
}
/**
* Load message bundle and place it into <code>msg</code> template attribute. Also load Theme properties and place them into <code>properties</code> template attribute.
*
* @param theme actual Theme to load bundle from
* @param locale to load bundle for
* @return message bundle for other use
*/
protected Properties handleThemeResources(Theme theme, Locale locale) {
Properties messagesBundle;
Locale locale = session.getContext().resolveLocale(user);
try {
messagesBundle = theme.getMessages(locale);
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
@ -343,6 +286,24 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
messagesBundle = new Properties();
}
try {
attributes.put("properties", theme.getProperties());
} catch (IOException e) {
logger.warn("Failed to load properties", e);
}
return messagesBundle;
}
/**
* Handle messages to be shown on the page - set them to template attributes
*
* @param locale to be used for message text loading
* @param messagesBundle to be used for message text loading
* @see #messageType
* @see #messages
*/
protected void handleMessages(Locale locale, Properties messagesBundle) {
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
if (messages != null) {
MessageBean wholeMessage = new MessageBean(null, messageType);
@ -354,11 +315,31 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
}
attributes.put("message", wholeMessage);
} else {
attributes.put("message", null);
}
attributes.put("messagesPerField", messagesPerField);
}
/**
* Create common attributes used in all templates.
*
* @param theme actual Theme used (provided by <code>getTheme()</code>)
* @param locale actual locale
* @param messagesBundle actual message bundle (provided by <code>handleThemeResources()</code>)
* @param baseUriBuilder actual base uri builder (provided by <code>prepareBaseUriBuilder()</code>)
* @param page in case if common page is rendered, is null if called from <code>createForm()</code>
*
*/
protected void createCommonAttributes(Theme theme, Locale locale, Properties messagesBundle, UriBuilder baseUriBuilder, LoginFormsPages page) {
URI baseUri = baseUriBuilder.build();
if (accessCode != null) {
baseUriBuilder.queryParam(OAuth2Constants.CODE, accessCode);
}
URI baseUriWithCodeAndClientId = baseUriBuilder.build();
if (status == null) {
status = Response.Status.OK;
if (client != null) {
attributes.put("client", new ClientBean(client, baseUri));
}
if (realm != null) {
@ -366,14 +347,29 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData);
attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCode));
attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUriWithCodeAndClientId));
attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));
attributes.put("requiredActionUrl", new RequiredActionUrlFormatterMethod(realm, baseUri));
if (realm.isInternationalizationEnabled()) {
UriBuilder b = UriBuilder.fromUri(baseUri)
.path(uriInfo.getPath());
UriBuilder b;
if (page != null) {
switch (page) {
case LOGIN:
b = UriBuilder.fromUri(Urls.realmLoginPage(baseUri, realm.getName()));
break;
case REGISTER:
b = UriBuilder.fromUri(Urls.realmRegisterPage(baseUri, realm.getName()));
break;
default:
b = UriBuilder.fromUri(baseUri).path(uriInfo.getPath());
break;
}
} else {
b = UriBuilder.fromUri(baseUri)
.path(uriInfo.getPath());
}
if (execution != null) {
b.queryParam(Constants.EXECUTION, execution);
@ -385,8 +381,19 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
if (realm != null && user != null && session != null) {
attributes.put("authenticatorConfigured", new AuthenticatorConfiguredMethod(realm, user, session));
}
}
/**
* Process FreeMarker template and prepare Response. Some fields are used for rendering also.
*
* @param theme to be used (provided by <code>getTheme()</code>)
* @param templateName name of the template to be rendered
* @param locale to be used
* @return Response object to be returned to the browser, never null
*/
protected Response processTemplate(Theme theme, String templateName, Locale locale) {
try {
String result = freeMarker.processTemplate(attributes, form, theme);
String result = freeMarker.processTemplate(attributes, templateName, theme);
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML_UTF_8_TYPE).language(locale).entity(result);
BrowserSecurityHeaderSetup.headers(builder, realm);
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
@ -434,7 +441,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return createResponse(LoginFormsPages.LOGIN_UPDATE_PROFILE);
}
@Override
public Response createIdpLinkConfirmLinkPage() {
return createResponse(LoginFormsPages.LOGIN_IDP_LINK_CONFIRM);
@ -504,7 +510,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
@Override
public LoginFormsProvider setErrors(List<FormMessage> messages) {
if (messages == null) return this;
if (messages == null)
return this;
this.messageType = MessageType.ERROR;
this.messages = new ArrayList<>(messages);
return this;
@ -552,6 +559,12 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return this;
}
@Override
public LoginFormsProvider setAuthenticationSession(AuthenticationSessionModel authenticationSession) {
this.authenticationSession = authenticationSession;
return this;
}
@Override
public FreeMarkerLoginFormsProvider setUser(UserModel user) {
this.user = user;
@ -571,7 +584,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
@Override
public LoginFormsProvider setAccessRequest(List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested, List<ProtocolMapperModel> protocolMappersRequested) {
public LoginFormsProvider setAccessRequest(List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested,
List<ProtocolMapperModel> protocolMappersRequested) {
this.realmRolesRequested = realmRolesRequested;
this.resourceRolesRequested = resourceRolesRequested;
this.protocolMappersRequested = protocolMappersRequested;

View file

@ -153,7 +153,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
action = Action.REGISTER;
if (!realm.isRegistrationAllowed()) {
throw new ErrorPageException(session, Messages.REGISTRATION_NOT_ALLOWED);
throw new ErrorPageException(session, authenticationSession, Messages.REGISTRATION_NOT_ALLOWED);
}
return this;
@ -164,7 +164,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
action = Action.FORGOT_CREDENTIALS;
if (!realm.isResetPasswordAllowed()) {
throw new ErrorPageException(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
throw new ErrorPageException(session, authenticationSession, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
}
return this;
@ -173,7 +173,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
private void checkClient(String clientId) {
if (clientId == null) {
event.error(Errors.INVALID_REQUEST);
throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM);
throw new ErrorPageException(session, authenticationSession, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM);
}
event.client(clientId);
@ -181,17 +181,17 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
client = realm.getClientByClientId(clientId);
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
throw new ErrorPageException(session, Messages.CLIENT_NOT_FOUND);
throw new ErrorPageException(session, authenticationSession, Messages.CLIENT_NOT_FOUND);
}
if (!client.isEnabled()) {
event.error(Errors.CLIENT_DISABLED);
throw new ErrorPageException(session, Messages.CLIENT_DISABLED);
throw new ErrorPageException(session, authenticationSession, Messages.CLIENT_DISABLED);
}
if (client.isBearerOnly()) {
event.error(Errors.NOT_ALLOWED);
throw new ErrorPageException(session, Messages.BEARER_ONLY);
throw new ErrorPageException(session, authenticationSession, Messages.BEARER_ONLY);
}
session.getContext().setClient(client);
@ -354,7 +354,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUriParam, realm, client, isOIDCRequest);
if (redirectUri == null) {
event.error(Errors.INVALID_REDIRECT_URI);
throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM);
throw new ErrorPageException(session, authenticationSession, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM);
}
}

View file

@ -107,7 +107,7 @@ public class LogoutEndpoint {
event.event(EventType.LOGOUT);
event.detail(Details.REDIRECT_URI, redirect);
event.error(Errors.INVALID_REDIRECT_URI);
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
return ErrorPage.error(session, null, Messages.INVALID_REDIRECT_URI);
}
redirect = validatedUri;
}
@ -120,7 +120,7 @@ public class LogoutEndpoint {
} catch (OAuthErrorException e) {
event.event(EventType.LOGOUT);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE);
return ErrorPage.error(session, null, Messages.SESSION_NOT_ACTIVE);
}
}

View file

@ -173,7 +173,7 @@ public class SamlProtocol implements LoginProtocol {
URI redirect = builder.buildFromMap(params);
return Response.status(302).location(redirect).build();
} else {
return ErrorPage.error(session, translateErrorToIdpInitiatedErrorMessage(error));
return ErrorPage.error(session, authSession, translateErrorToIdpInitiatedErrorMessage(error));
}
} else {
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder().destination(authSession.getRedirectUri()).issuer(getResponseIssuer(realm)).status(translateErrorToSAMLStatus(error).get());
@ -196,7 +196,7 @@ public class SamlProtocol implements LoginProtocol {
Document document = builder.buildDocument();
return buildErrorResponse(authSession, binding, document);
} catch (Exception e) {
return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
return ErrorPage.error(session, authSession, Messages.FAILED_TO_PROCESS_RESPONSE);
}
}
} finally {
@ -427,7 +427,7 @@ public class SamlProtocol implements LoginProtocol {
samlDocument = builder.buildDocument(samlModel);
} catch (Exception e) {
logger.error("failed", e);
return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
return ErrorPage.error(session, null, Messages.FAILED_TO_PROCESS_RESPONSE);
}
JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder();
@ -453,7 +453,7 @@ public class SamlProtocol implements LoginProtocol {
publicKey = SamlProtocolUtils.getEncryptionKey(client);
} catch (Exception e) {
logger.error("failed", e);
return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
return ErrorPage.error(session, null, Messages.FAILED_TO_PROCESS_RESPONSE);
}
bindingBuilder.encrypt(publicKey);
}
@ -461,7 +461,7 @@ public class SamlProtocol implements LoginProtocol {
return buildAuthenticatedResponse(clientSession, redirectUri, samlDocument, bindingBuilder);
} catch (Exception e) {
logger.error("failed", e);
return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
return ErrorPage.error(session, null, Messages.FAILED_TO_PROCESS_RESPONSE);
}
}
@ -568,7 +568,7 @@ public class SamlProtocol implements LoginProtocol {
String logoutBindingUri = userSession.getNote(SAML_LOGOUT_BINDING_URI);
if (logoutBindingUri == null) {
logger.error("Can't finish SAML logout as there is no logout binding set. Please configure the logout service url in the admin console for your client applications.");
return ErrorPage.error(session, Messages.FAILED_LOGOUT);
return ErrorPage.error(session, null, Messages.FAILED_LOGOUT);
}
String logoutRelayState = userSession.getNote(SAML_LOGOUT_RELAY_STATE);

View file

@ -118,18 +118,18 @@ public class SamlService extends AuthorizationEndpointBase {
if (!checkSsl()) {
event.event(EventType.LOGIN);
event.error(Errors.SSL_REQUIRED);
return ErrorPage.error(session, Messages.HTTPS_REQUIRED);
return ErrorPage.error(session, null, Messages.HTTPS_REQUIRED);
}
if (!realm.isEnabled()) {
event.event(EventType.LOGIN_ERROR);
event.error(Errors.REALM_DISABLED);
return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
return ErrorPage.error(session, null, Messages.REALM_NOT_ENABLED);
}
if (samlRequest == null && samlResponse == null) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
return null;
@ -142,7 +142,7 @@ public class SamlService extends AuthorizationEndpointBase {
if (! (holder.getSamlObject() instanceof StatusResponseType)) {
event.detail(Details.REASON, "invalid_saml_response");
event.error(Errors.INVALID_SAML_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
StatusResponseType statusResponse = (StatusResponseType) holder.getSamlObject();
@ -150,7 +150,7 @@ public class SamlService extends AuthorizationEndpointBase {
if (statusResponse.getDestination() != null && !uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) {
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false);
@ -158,7 +158,7 @@ public class SamlService extends AuthorizationEndpointBase {
logger.warn("Unknown saml response.");
event.event(EventType.LOGOUT);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
// assume this is a logout response
UserSessionModel userSession = authResult.getSession();
@ -167,7 +167,7 @@ public class SamlService extends AuthorizationEndpointBase {
logger.warn("UserSession is not tagged as logging out.");
event.event(EventType.LOGOUT);
event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
logger.debug("logout response");
Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
@ -180,7 +180,7 @@ public class SamlService extends AuthorizationEndpointBase {
if (documentHolder == null) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
SAML2Object samlObject = documentHolder.getSamlObject();
@ -188,7 +188,7 @@ public class SamlService extends AuthorizationEndpointBase {
if (! (samlObject instanceof RequestAbstractType)) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
RequestAbstractType requestAbstractType = (RequestAbstractType) samlObject;
@ -199,23 +199,23 @@ public class SamlService extends AuthorizationEndpointBase {
event.event(EventType.LOGIN);
event.client(issuer);
event.error(Errors.CLIENT_NOT_FOUND);
return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
return ErrorPage.error(session, null, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
event.event(EventType.LOGIN);
event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
return ErrorPage.error(session, null, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
if (client.isBearerOnly()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.BEARER_ONLY);
return ErrorPage.error(session, null, Messages.BEARER_ONLY);
}
if (!client.isStandardFlowEnabled()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.STANDARD_FLOW_DISABLED);
return ErrorPage.error(session, null, Messages.STANDARD_FLOW_DISABLED);
}
session.getContext().setClient(client);
@ -226,7 +226,7 @@ public class SamlService extends AuthorizationEndpointBase {
SamlService.logger.error("request validation failed", e);
event.event(EventType.LOGIN);
event.error(Errors.INVALID_SIGNATURE);
return ErrorPage.error(session, Messages.INVALID_REQUESTER);
return ErrorPage.error(session, null, Messages.INVALID_REQUESTER);
}
logger.debug("verified request");
if (samlObject instanceof AuthnRequestType) {
@ -244,7 +244,7 @@ public class SamlService extends AuthorizationEndpointBase {
} else {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
}
@ -260,12 +260,12 @@ public class SamlService extends AuthorizationEndpointBase {
if (requestAbstractType.getDestination() == null && samlClient.requiresClientSignature()) {
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
if (! isValidDestination(requestAbstractType.getDestination())) {
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
String bindingType = getBindingType(requestAbstractType);
if (samlClient.forcePostBinding())
@ -288,7 +288,7 @@ public class SamlService extends AuthorizationEndpointBase {
if (redirect == null) {
event.error(Errors.INVALID_REDIRECT_URI);
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
return ErrorPage.error(session, null, Messages.INVALID_REDIRECT_URI);
}
AuthorizationEndpointChecks checks = getOrCreateAuthenticationSession(client, relayState);
@ -316,7 +316,7 @@ public class SamlService extends AuthorizationEndpointBase {
} else {
event.detail(Details.REASON, "unsupported_nameid_format");
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
return ErrorPage.error(session, Messages.UNSUPPORTED_NAME_ID_FORMAT);
return ErrorPage.error(session, null, Messages.UNSUPPORTED_NAME_ID_FORMAT);
}
}
@ -367,12 +367,12 @@ public class SamlService extends AuthorizationEndpointBase {
if (logoutRequest.getDestination() == null && samlClient.requiresClientSignature()) {
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_LOGOUT_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
if (! isValidDestination(logoutRequest.getDestination())) {
event.detail(Details.REASON, "invalid_destination");
event.error(Errors.INVALID_SAML_LOGOUT_REQUEST);
return ErrorPage.error(session, Messages.INVALID_REQUEST);
return ErrorPage.error(session, null, Messages.INVALID_REQUEST);
}
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
@ -620,16 +620,16 @@ public class SamlService extends AuthorizationEndpointBase {
}
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
return ErrorPage.error(session, Messages.CLIENT_NOT_FOUND);
return ErrorPage.error(session, null, Messages.CLIENT_NOT_FOUND);
}
if (!client.isEnabled()) {
event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.CLIENT_DISABLED);
return ErrorPage.error(session, null, Messages.CLIENT_DISABLED);
}
if (client.getManagementUrl() == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE) == null) {
logger.error("SAML assertion consumer url not set up");
event.error(Errors.INVALID_REDIRECT_URI);
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
return ErrorPage.error(session, null, Messages.INVALID_REDIRECT_URI);
}
AuthenticationSessionModel authSession = getOrCreateLoginSessionForIdpInitiatedSso(this.session, this.realm, client, relayState);

View file

@ -18,6 +18,7 @@ package org.keycloak.services;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
@ -26,8 +27,8 @@ import javax.ws.rs.core.Response;
*/
public class ErrorPage {
public static Response error(KeycloakSession session, String message, Object... parameters) {
return session.getProvider(LoginFormsProvider.class).setError(message, parameters).createErrorPage();
public static Response error(KeycloakSession session, AuthenticationSessionModel authenticationSession, String message, Object... parameters) {
return session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authenticationSession).setError(message, parameters).createErrorPage();
}

View file

@ -18,6 +18,7 @@
package org.keycloak.services;
import org.keycloak.models.KeycloakSession;
import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
@ -30,18 +31,28 @@ public class ErrorPageException extends WebApplicationException {
private final KeycloakSession session;
private final String errorMessage;
private final Object[] parameters;
private final AuthenticationSessionModel authSession;
public ErrorPageException(KeycloakSession session, String errorMessage, Object... parameters) {
this.session = session;
this.errorMessage = errorMessage;
this.parameters = parameters;
this.authSession = null;
}
public ErrorPageException(KeycloakSession session, AuthenticationSessionModel authSession, String errorMessage, Object... parameters) {
this.session = session;
this.errorMessage = errorMessage;
this.parameters = parameters;
this.authSession = authSession;
}
@Override
public Response getResponse() {
return ErrorPage.error(session, errorMessage, parameters);
return ErrorPage.error(session, authSession, errorMessage, parameters);
}
}

View file

@ -710,7 +710,7 @@ public class AuthenticationManager {
}
if (authSession.getAuthNote(END_AFTER_REQUIRED_ACTIONS) != null) {
LoginFormsProvider infoPage = session.getProvider(LoginFormsProvider.class)
LoginFormsProvider infoPage = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession)
.setSuccess(Messages.ACCOUNT_UPDATED);
if (authSession.getAuthNote(SET_REDIRECT_URI_AFTER_REQUIRED_ACTIONS) != null) {
if (authSession.getRedirectUri() != null) {
@ -848,6 +848,7 @@ public class AuthenticationManager {
authSession.setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution);
return session.getProvider(LoginFormsProvider.class)
.setAuthenticationSession(authSession)
.setExecution(execution)
.setClientSessionCode(accessCode.getOrGenerateCode())
.setAccessRequest(realmRoles, resourceRoles, protocolMappers)

View file

@ -317,12 +317,12 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return response;
}
} catch (IdentityBrokerException e) {
return redirectToErrorPage(Messages.COULD_NOT_SEND_AUTHENTICATION_REQUEST, e, providerId);
return redirectToErrorPage(authSession, Messages.COULD_NOT_SEND_AUTHENTICATION_REQUEST, e, providerId);
} catch (Exception e) {
return redirectToErrorPage(Messages.UNEXPECTED_ERROR_HANDLING_REQUEST, e, providerId);
return redirectToErrorPage(authSession, Messages.UNEXPECTED_ERROR_HANDLING_REQUEST, e, providerId);
}
return redirectToErrorPage(Messages.COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST);
return redirectToErrorPage(authSession, Messages.COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST);
}
@ -545,7 +545,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return Response.status(302).location(redirect).build();
} else {
Response response = validateUser(federatedUser, realmModel);
Response response = validateUser(authenticationSession, federatedUser, realmModel);
if (response != null) {
return response;
}
@ -558,15 +558,15 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
public Response validateUser(UserModel user, RealmModel realm) {
public Response validateUser(AuthenticationSessionModel authSession, UserModel user, RealmModel realm) {
if (!user.isEnabled()) {
event.error(Errors.USER_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
return ErrorPage.error(session, authSession, Messages.ACCOUNT_DISABLED);
}
if (realm.isBruteForceProtected()) {
if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
event.error(Errors.USER_TEMPORARILY_DISABLED);
return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
return ErrorPage.error(session, authSession, Messages.ACCOUNT_DISABLED);
}
}
return null;
@ -670,7 +670,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return finishOrRedirectToPostBrokerLogin(authSession, context, true, clientSessionCode);
} catch (Exception e) {
return redirectToErrorPage(Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
return redirectToErrorPage(authSession,Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
}
}
@ -734,7 +734,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return afterPostBrokerLoginFlowSuccess(authenticationSession, context, wasFirstBrokerLogin, parsedCode.clientSessionCode);
} catch (IdentityBrokerException e) {
return redirectToErrorPage(Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
return redirectToErrorPage(authenticationSession, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
}
}
@ -752,7 +752,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realmModel, authSession);
if (!linkingUser.getId().equals(federatedUser.getId())) {
return redirectToErrorPage(Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, federatedUser.getUsername(), linkingUser.getUsername());
return redirectToErrorPage(authSession, Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, federatedUser.getUsername(), linkingUser.getUsername());
}
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
@ -866,7 +866,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
if (!authenticatedUser.hasRole(this.realmModel.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.MANAGE_ACCOUNT))) {
return redirectToErrorPage(Messages.INSUFFICIENT_PERMISSION);
return redirectToErrorPage(authSession, Messages.INSUFFICIENT_PERMISSION);
}
if (!authenticatedUser.isEnabled()) {
@ -919,7 +919,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
if (authSession.getClient() != null && authSession.getClient().getClientId().equals(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)) {
return redirectToAccountErrorPage(authSession, message, parameters);
} else {
return redirectToErrorPage(message, parameters); // Should rather redirect to app instead and display error here?
return redirectToErrorPage(authSession, message, parameters); // Should rather redirect to app instead and display error here?
}
}
@ -1057,11 +1057,15 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return Urls.identityProviderAuthnResponse(this.uriInfo.getBaseUri(), providerId, this.realmModel.getName()).toString();
}
private Response redirectToErrorPage(AuthenticationSessionModel authSession,String message, Object ... parameters) {
return redirectToErrorPage(authSession, message, null, parameters);
}
private Response redirectToErrorPage(String message, Object ... parameters) {
return redirectToErrorPage(message, null, parameters);
return redirectToErrorPage(null, message, null, parameters);
}
private Response redirectToErrorPage(String message, Throwable throwable, Object ... parameters) {
private Response redirectToErrorPage(AuthenticationSessionModel authSession, String message, Throwable throwable, Object ... parameters) {
if (message == null) {
message = Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR;
}
@ -1073,7 +1077,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return webEx.getResponse();
}
return ErrorPage.error(this.session, message, parameters);
return ErrorPage.error(this.session, authSession, message, parameters);
}
private Response redirectToAccountErrorPage(AuthenticationSessionModel authSession, String message, Object ... parameters) {

View file

@ -340,7 +340,7 @@ public class LoginActionsService {
if (!realm.isResetPasswordAllowed()) {
event.event(EventType.RESET_PASSWORD);
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
return ErrorPage.error(session, authSession, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
}
authSession = createAuthenticationSessionForClient();
@ -384,7 +384,7 @@ public class LoginActionsService {
if (!realm.isResetPasswordAllowed()) {
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
return ErrorPage.error(session, authSession, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
}
@ -553,7 +553,7 @@ public class LoginActionsService {
} else if (RESET_CREDENTIALS_PATH.equals(flowPath)) {
return processResetCredentials(false, null, authSession, errorMessage);
} else {
return ErrorPage.error(session, errorMessage == null ? Messages.INVALID_REQUEST : errorMessage);
return ErrorPage.error(session, authSession, errorMessage == null ? Messages.INVALID_REQUEST : errorMessage);
}
}
@ -577,7 +577,7 @@ public class LoginActionsService {
event
.detail(Details.REASON, ex == null ? "<unknown>" : ex.getMessage())
.error(eventError == null ? Errors.INVALID_CODE : eventError);
return ErrorPage.error(session, errorMessage == null ? Messages.INVALID_CODE : errorMessage);
return ErrorPage.error(session, null, errorMessage == null ? Messages.INVALID_CODE : errorMessage);
}
protected Response processResetCredentials(boolean actionRequest, String execution, AuthenticationSessionModel authSession, String errorMessage) {
@ -626,7 +626,7 @@ public class LoginActionsService {
event.event(EventType.REGISTER);
if (!realm.isRegistrationAllowed()) {
event.error(Errors.REGISTRATION_DISABLED);
return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED);
return ErrorPage.error(session, null, Messages.REGISTRATION_NOT_ALLOWED);
}
SessionCodeChecks checks = checksForCode(code, execution, clientId, REGISTRATION_PATH);
@ -692,7 +692,7 @@ public class LoginActionsService {
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, noteKey);
if (serializedCtx == null) {
ServicesLogger.LOGGER.notFoundSerializedCtxInClientSession(noteKey);
throw new WebApplicationException(ErrorPage.error(session, "Not found serialized context in authenticationSession."));
throw new WebApplicationException(ErrorPage.error(session, authSession, "Not found serialized context in authenticationSession."));
}
BrokeredIdentityContext brokerContext = serializedCtx.deserialize(session, authSession);
final String identityProviderAlias = brokerContext.getIdpConfig().getAlias();
@ -700,12 +700,12 @@ public class LoginActionsService {
String flowId = firstBrokerLogin ? brokerContext.getIdpConfig().getFirstBrokerLoginFlowId() : brokerContext.getIdpConfig().getPostBrokerLoginFlowId();
if (flowId == null) {
ServicesLogger.LOGGER.flowNotConfigForIDP(identityProviderAlias);
throw new WebApplicationException(ErrorPage.error(session, "Flow not configured for identity provider"));
throw new WebApplicationException(ErrorPage.error(session, authSession, "Flow not configured for identity provider"));
}
AuthenticationFlowModel brokerLoginFlow = realm.getAuthenticationFlowById(flowId);
if (brokerLoginFlow == null) {
ServicesLogger.LOGGER.flowNotFoundForIDP(flowId, identityProviderAlias);
throw new WebApplicationException(ErrorPage.error(session, "Flow not found for identity provider"));
throw new WebApplicationException(ErrorPage.error(session, authSession, "Flow not found for identity provider"));
}
event.detail(Details.IDENTITY_PROVIDER, identityProviderAlias)
@ -886,7 +886,7 @@ public class LoginActionsService {
if (factory == null) {
ServicesLogger.LOGGER.actionProviderNull();
event.error(Errors.INVALID_CODE);
throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
throw new WebApplicationException(ErrorPage.error(session, authSession, Messages.INVALID_CODE));
}
RequiredActionProvider provider = factory.create(session);

View file

@ -116,7 +116,7 @@ public class LoginActionsServiceChecks {
UserSessionModel userSession = context.getSession().sessions().getUserSession(context.getRealm(), authSessionId);
if (userSession != null) {
LoginFormsProvider loginForm = context.getSession().getProvider(LoginFormsProvider.class)
LoginFormsProvider loginForm = context.getSession().getProvider(LoginFormsProvider.class).setAuthenticationSession(context.getAuthenticationSession())
.setSuccess(Messages.ALREADY_LOGGED_IN);
if (context.getSession().getContext().getClient() == null) {

View file

@ -123,12 +123,12 @@ public class SessionCodeChecks {
// Basic realm checks
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
response = ErrorPage.error(session, Messages.HTTPS_REQUIRED);
response = ErrorPage.error(session, null, Messages.HTTPS_REQUIRED);
return null;
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
response = ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
response = ErrorPage.error(session, null, Messages.REALM_NOT_ENABLED);
return null;
}
@ -154,7 +154,7 @@ public class SessionCodeChecks {
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
if (userSession != null) {
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class)
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession)
.setSuccess(Messages.ALREADY_LOGGED_IN);
if (client == null) {
@ -190,7 +190,7 @@ public class SessionCodeChecks {
ClientModel client = authSession.getClient();
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
response = ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
response = ErrorPage.error(session, authSession, Messages.UNKNOWN_LOGIN_REQUESTER);
clientCode.removeExpiredClientSession();
return false;
}
@ -200,7 +200,7 @@ public class SessionCodeChecks {
if (!client.isEnabled()) {
event.error(Errors.CLIENT_DISABLED);
response = ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
response = ErrorPage.error(session,authSession, Messages.LOGIN_REQUESTER_NOT_ENABLED);
clientCode.removeExpiredClientSession();
return false;
}
@ -285,7 +285,7 @@ public class SessionCodeChecks {
return false;
} else {
logger.errorf("Bad action. Expected action '%s', current action '%s'", expectedAction, authSession.getAction());
response = ErrorPage.error(session, Messages.EXPIRED_CODE);
response = ErrorPage.error(session, authSession, Messages.EXPIRED_CODE);
return false;
}
}
@ -370,7 +370,7 @@ public class SessionCodeChecks {
} else {
// Finally need to show error as all the fallbacks failed
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, Messages.INVALID_CODE);
return ErrorPage.error(session, authSession, Messages.INVALID_CODE);
}
}

View file

@ -56,7 +56,7 @@ public class AuthenticationFlowURLHelper {
logger.debugf("Redirecting to 'page expired' now. Will use last step URL: %s", lastStepUrl);
return session.getProvider(LoginFormsProvider.class)
return session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession)
.setActionUri(lastStepUrl)
.setExecution(getExecutionId(authSession))
.createLoginExpiredPage();

View file

@ -191,14 +191,13 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
return callback.cancelled(state);
}
Response errorResponse = null;
AuthenticationSessionModel authSession = null;
try {
Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(getConfig().getClientId(), getConfig().getClientSecret());
AuthenticationSessionModel authSession = ClientSessionCode.getClientSession(state, session, realm, event, AuthenticationSessionModel.class);
authSession = ClientSessionCode.getClientSession(state, session, realm, event, AuthenticationSessionModel.class);
String twitterToken = authSession.getAuthNote(TWITTER_TOKEN);
String twitterSecret = authSession.getAuthNote(TWITTER_TOKENSECRET);
@ -239,7 +238,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
} catch (Exception e) {
logger.error("Could get user profile from twitter.", e);
sendErrorEvent();
return ErrorPage.error(session, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE);
return ErrorPage.error(session, authSession, Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE);
}
}