diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java index c65e8713ce..0a525a4454 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java @@ -34,7 +34,7 @@ import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; import javax.ws.rs.GET; import javax.ws.rs.QueryParam; @@ -217,7 +217,7 @@ public abstract class AbstractOAuth2IdentityProvider + diff --git a/events/jboss-logging/pom.xml b/events/jboss-logging/pom.xml index cf05f963eb..0f407d4f96 100755 --- a/events/jboss-logging/pom.xml +++ b/events/jboss-logging/pom.xml @@ -36,6 +36,11 @@ ${project.version} provided + + org.jboss.resteasy + resteasy-jaxrs + provided + junit junit diff --git a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java index badc0eea93..dba4304bf9 100755 --- a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java +++ b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProvider.java @@ -3,23 +3,35 @@ package org.keycloak.events.log; import org.jboss.logging.Logger; import org.keycloak.events.Event; import org.keycloak.events.EventListenerProvider; +import org.keycloak.models.KeycloakContext; +import org.keycloak.models.KeycloakSession; +import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; import java.util.Map; +import java.util.logging.Level; /** * @author Stian Thorgersen */ public class JBossLoggingEventListenerProvider implements EventListenerProvider { + private final KeycloakSession session; private final Logger logger; + private final Logger.Level successLevel; + private final Logger.Level errorLevel; - public JBossLoggingEventListenerProvider(Logger logger) { + public JBossLoggingEventListenerProvider(KeycloakSession session, Logger logger, Logger.Level successLevel, Logger.Level errorLevel) { + this.session = session; this.logger = logger; + this.successLevel = successLevel; + this.errorLevel = errorLevel; } @Override public void onEvent(Event event) { - Logger.Level level = event.getError() != null ? Logger.Level.WARN : Logger.Level.INFO; + Logger.Level level = event.getError() != null ? errorLevel : successLevel; if (logger.isEnabled(level)) { StringBuilder sb = new StringBuilder(); @@ -55,7 +67,31 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider } } - logger.log(level, sb.toString()); + if (logger.isTraceEnabled()) { + KeycloakContext context = session.getContext(); + UriInfo uriInfo = context.getUri(); + HttpHeaders headers = context.getRequestHeaders(); + if (uriInfo != null) { + sb.append(", requestUri="); + sb.append(uriInfo.getRequestUri().toString()); + } + + if (headers != null) { + sb.append(", cookies=["); + boolean f = true; + for (Map.Entry e : headers.getCookies().entrySet()) { + if (f) { + f = false; + } else { + sb.append(", "); + } + sb.append(e.getValue().toString()); + } + sb.append("]"); + } + } + + logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString()); } } diff --git a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProviderFactory.java b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProviderFactory.java index 1c91ceabd6..07ae4e2b9c 100755 --- a/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProviderFactory.java +++ b/events/jboss-logging/src/main/java/org/keycloak/events/log/JBossLoggingEventListenerProviderFactory.java @@ -6,6 +6,9 @@ import org.keycloak.events.EventListenerProvider; import org.keycloak.events.EventListenerProviderFactory; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import sun.rmi.runtime.Log; + +import java.util.logging.Level; /** * @author Stian Thorgersen @@ -16,13 +19,18 @@ public class JBossLoggingEventListenerProviderFactory implements EventListenerPr private static final Logger logger = Logger.getLogger("org.keycloak.events"); + private Logger.Level successLevel; + private Logger.Level errorLevel; + @Override public EventListenerProvider create(KeycloakSession session) { - return new JBossLoggingEventListenerProvider(logger); + return new JBossLoggingEventListenerProvider(session, logger, successLevel, errorLevel); } @Override public void init(Config.Scope config) { + successLevel = Logger.Level.valueOf(config.get("success-level", "debug").toUpperCase()); + errorLevel = Logger.Level.valueOf(config.get("error-level", "warn").toUpperCase()); } @Override diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java index cb3949a492..fe38f2cbaa 100755 --- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java +++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java @@ -47,7 +47,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.FormMessage; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; /** * @author Stian Thorgersen diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java index 685ff45b61..1c779badc1 100755 --- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java +++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountFederatedIdentityBean.java @@ -6,7 +6,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.services.resources.AccountService; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.core.UriBuilder; import java.net.URI; diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java index de7e432d6a..001ffde11c 100755 --- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java +++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java @@ -2,7 +2,7 @@ package org.keycloak.account.freemarker.model; import org.keycloak.freemarker.Theme; import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import java.net.URI; diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java index c3a71d9a94..8e5ef24b7f 100755 --- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java +++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java @@ -21,12 +21,6 @@ import org.keycloak.provider.Provider; */ public interface LoginFormsProvider extends Provider { - public LoginFormsProvider setRealm(RealmModel realm); - - public LoginFormsProvider setUriInfo(UriInfo uriInfo); - - public LoginFormsProvider setHttpHeaders(HttpHeaders httpHeaders); - public Response createResponse(UserModel.RequiredAction action); public Response createLogin(); @@ -67,14 +61,8 @@ public interface LoginFormsProvider extends Provider { public LoginFormsProvider setSuccess(String message, Object ... parameters); - public LoginFormsProvider setWarning(String message, Object ... parameters); - public LoginFormsProvider setUser(UserModel user); - public LoginFormsProvider setClient(ClientModel client); - - public LoginFormsProvider setQueryParams(MultivaluedMap queryParams); - public LoginFormsProvider setResponseHeader(String headerName, String headerValue); public LoginFormsProvider setFormData(MultivaluedMap formData); diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java index 228a1466cd..7e5cb78ac3 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java @@ -37,9 +37,8 @@ import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; @@ -79,39 +78,20 @@ import java.util.concurrent.TimeUnit; private KeycloakSession session; private FreeMarkerUtil freeMarker; - private RealmModel realm; private UserModel user; - private ClientModel client; private ClientSessionModel clientSession; - private UriInfo uriInfo; - - private HttpHeaders httpHeaders; - public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) { this.session = session; this.freeMarker = freeMarker; } - public LoginFormsProvider setRealm(RealmModel realm) { - this.realm = realm; - return this; - } - - public LoginFormsProvider setUriInfo(UriInfo uriInfo) { - this.uriInfo = uriInfo; - return this; - } - - @Override - public LoginFormsProvider setHttpHeaders(HttpHeaders httpHeaders) { - this.httpHeaders = httpHeaders; - return this; - } - public Response createResponse(UserModel.RequiredAction action) { + RealmModel realm = session.getContext().getRealm(); + UriInfo uriInfo = session.getContext().getUri(); + String actionMessage; LoginFormsPages page; @@ -150,13 +130,17 @@ import java.util.concurrent.TimeUnit; } if (messages == null) { - setWarning(actionMessage); + setMessage(MessageType.WARNING, actionMessage); } return createResponse(page); } private Response createResponse(LoginFormsPages page) { + RealmModel realm = session.getContext().getRealm(); + ClientModel client = session.getContext().getClient(); + UriInfo uriInfo = session.getContext().getUri(); + MultivaluedMap queryParameterMap = queryParams != null ? queryParams : new MultivaluedMapImpl(); String requestURI = uriInfo.getBaseUri().getPath(); @@ -191,7 +175,7 @@ import java.util.concurrent.TimeUnit; } Properties messagesBundle; - Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, httpHeaders); + Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, session.getContext().getRequestHeaders()); try { messagesBundle = theme.getMessages(locale); attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle)); @@ -222,7 +206,7 @@ import java.util.concurrent.TimeUnit; if (realm != null) { attributes.put("realm", new RealmBean(realm)); - attributes.put("social", new IdentityProviderBean(realm, baseUri, this.uriInfo)); + attributes.put("social", new IdentityProviderBean(realm, baseUri, uriInfo)); attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri)); if (realm.isInternationalizationEnabled()) { @@ -365,22 +349,11 @@ import java.util.concurrent.TimeUnit; return this; } - @Override - public FreeMarkerLoginFormsProvider setWarning(String message, Object ... parameters) { - setMessage(MessageType.WARNING, message, parameters); - return this; - } - public FreeMarkerLoginFormsProvider setUser(UserModel user) { this.user = user; return this; } - public FreeMarkerLoginFormsProvider setClient(ClientModel client) { - this.client = client; - return this; - } - public FreeMarkerLoginFormsProvider setFormData(MultivaluedMap formData) { this.formData = formData; return this; @@ -411,12 +384,6 @@ import java.util.concurrent.TimeUnit; return this; } - @Override - public LoginFormsProvider setQueryParams(MultivaluedMap queryParams) { - this.queryParams = queryParams; - return this; - } - @Override public LoginFormsProvider setActionUri(URI actionUri) { this.actionUri = actionUri; diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java index 65e02723c7..23c6e69bd6 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java @@ -23,7 +23,7 @@ package org.keycloak.login.freemarker.model; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.core.UriInfo; import java.net.URI; diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java index eb9a40bfff..4c25bb317e 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java @@ -23,7 +23,7 @@ package org.keycloak.login.freemarker.model; import org.keycloak.freemarker.Theme; import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import java.net.URI; diff --git a/model/api/pom.xml b/model/api/pom.xml index 965349186a..1b97730c38 100755 --- a/model/api/pom.xml +++ b/model/api/pom.xml @@ -14,6 +14,11 @@ + + org.jboss.resteasy + resteasy-jaxrs + provided + net.iharder base64 diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakContext.java b/model/api/src/main/java/org/keycloak/models/KeycloakContext.java new file mode 100644 index 0000000000..ac13d3fbcc --- /dev/null +++ b/model/api/src/main/java/org/keycloak/models/KeycloakContext.java @@ -0,0 +1,23 @@ +package org.keycloak.models; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +/** + * @author Stian Thorgersen + */ +public interface KeycloakContext { + + UriInfo getUri(); + + HttpHeaders getRequestHeaders(); + + RealmModel getRealm(); + + void setRealm(RealmModel realm); + + ClientModel getClient(); + + void setClient(ClientModel client); + +} diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java index 3dc38e57c1..b6f35e6dbc 100755 --- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java +++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java @@ -10,6 +10,8 @@ import java.util.Set; */ public interface KeycloakSession { + KeycloakContext getContext(); + KeycloakTransactionManager getTransaction(); T getProvider(Class clazz); diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index f830ac1f24..0671641f87 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -64,7 +64,7 @@ public class RepresentationToModel { if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor()); if (rep.isEventsEnabled() != null) newRealm.setEventsEnabled(rep.isEventsEnabled()); if (rep.getEventsExpiration() != null) newRealm.setEventsExpiration(rep.getEventsExpiration()); - if (rep.getEventsListeners() != null) newRealm.setEventsListeners(new HashSet(rep.getEventsListeners())); + if (rep.getEventsListeners() != null) newRealm.setEventsListeners(new HashSet<>(rep.getEventsListeners())); if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore()); @@ -409,8 +409,8 @@ public class RepresentationToModel { if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme()); if (rep.isEventsEnabled() != null) realm.setEventsEnabled(rep.isEventsEnabled()); if (rep.getEventsExpiration() != null) realm.setEventsExpiration(rep.getEventsExpiration()); - if (rep.getEventsListeners() != null) realm.setEventsListeners(new HashSet(rep.getEventsListeners())); - if (rep.getEnabledEventTypes() != null) realm.setEnabledEventTypes(new HashSet(rep.getEnabledEventTypes())); + if (rep.getEventsListeners() != null) realm.setEventsListeners(new HashSet<>(rep.getEventsListeners())); + if (rep.getEnabledEventTypes() != null) realm.setEnabledEventTypes(new HashSet<>(rep.getEnabledEventTypes())); if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy())); diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java index b38d5b933e..747c43cea8 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java @@ -30,7 +30,7 @@ import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.admin.ClientAttributeCertificateResource; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; import org.w3c.dom.Document; import javax.ws.rs.core.HttpHeaders; @@ -152,7 +152,7 @@ public class SamlProtocol implements LoginProtocol { return builder.redirectBinding().response(); } } catch (Exception e) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE ); + return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } } @@ -309,7 +309,7 @@ public class SamlProtocol implements LoginProtocol { samlDocument = builder.buildDocument(samlModel); } catch (Exception e) { logger.error("failed", e); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo,headers, Messages.FAILED_TO_PROCESS_RESPONSE); + return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } SAML2BindingBuilder2 bindingBuilder = new SAML2BindingBuilder2(); @@ -331,7 +331,7 @@ public class SamlProtocol implements LoginProtocol { publicKey = SamlProtocolUtils.getEncryptionValidationKey(client); } catch (Exception e) { logger.error("failed", e); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE); + return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } bindingBuilder.encrypt(publicKey); } @@ -343,7 +343,7 @@ public class SamlProtocol implements LoginProtocol { } } catch (Exception e) { logger.error("failed", e); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE ); + return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE); } } diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java index 3b1ff99296..ff936e5156 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java @@ -23,7 +23,7 @@ import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.HttpAuthenticationManager; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; import org.keycloak.util.StreamUtil; import org.keycloak.saml.common.constants.GeneralConstants; import org.keycloak.saml.common.constants.JBossSAMLURIConstants; @@ -102,18 +102,18 @@ public class SamlService { if (!checkSsl()) { event.event(EventType.LOGIN); event.error(Errors.SSL_REQUIRED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED ); + return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } if (!realm.isEnabled()) { event.event(EventType.LOGIN_ERROR); event.error(Errors.REALM_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + return ErrorPage.error(session, Messages.REALM_NOT_ENABLED); } if (samlRequest == null && samlResponse == null) { event.event(EventType.LOGIN); event.error(Errors.INVALID_TOKEN); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST ); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } return null; @@ -127,7 +127,7 @@ public class SamlService { if (!uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) { event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE); event.detail(Details.REASON, "invalid_destination"); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false); @@ -135,7 +135,7 @@ public class SamlService { logger.warn("Unknown saml response."); event.event(EventType.LOGOUT); event.error(Errors.INVALID_TOKEN); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } // assume this is a logout response UserSessionModel userSession = authResult.getSession(); @@ -144,7 +144,7 @@ public class SamlService { logger.warn("UserSession is not tagged as logging out."); event.event(EventType.LOGOUT); event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } logger.debug("logout response"); Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers); @@ -157,7 +157,7 @@ public class SamlService { if (documentHolder == null) { event.event(EventType.LOGIN); event.error(Errors.INVALID_TOKEN); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } SAML2Object samlObject = documentHolder.getSamlObject(); @@ -169,32 +169,34 @@ public class SamlService { if (client == null) { event.event(EventType.LOGIN); event.error(Errors.CLIENT_NOT_FOUND); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER); + return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER); } if (!client.isEnabled()) { event.event(EventType.LOGIN); event.error(Errors.CLIENT_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED); + return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED); } if ((client instanceof ClientModel) && ((ClientModel)client).isBearerOnly()) { event.event(EventType.LOGIN); event.error(Errors.NOT_ALLOWED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.BEARER_ONLY); + return ErrorPage.error(session, Messages.BEARER_ONLY); } if (client.isDirectGrantsOnly()) { event.event(EventType.LOGIN); event.error(Errors.NOT_ALLOWED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.DIRECT_GRANTS_ONLY ); + return ErrorPage.error(session, Messages.DIRECT_GRANTS_ONLY); } + session.getContext().setClient(client); + try { verifySignature(documentHolder, client); } catch (VerificationException e) { SamlService.logger.error("request validation failed", e); event.event(EventType.LOGIN); event.error(Errors.INVALID_SIGNATURE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUESTER); + return ErrorPage.error(session, Messages.INVALID_REQUESTER); } logger.debug("verified request"); if (samlObject instanceof AuthnRequestType) { @@ -212,7 +214,7 @@ public class SamlService { } else { event.event(EventType.LOGIN); event.error(Errors.INVALID_TOKEN); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } } @@ -226,7 +228,7 @@ public class SamlService { if (!uriInfo.getAbsolutePath().equals(requestAbstractType.getDestination())) { event.error(Errors.INVALID_SAML_AUTHN_REQUEST); event.detail(Details.REASON, "invalid_destination"); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } String bindingType = getBindingType(requestAbstractType); if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING))) bindingType = SamlProtocol.SAML_POST_BINDING; @@ -248,7 +250,7 @@ public class SamlService { if (redirect == null) { event.error(Errors.INVALID_REDIRECT_URI); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI ); + return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI); } @@ -271,7 +273,7 @@ public class SamlService { } else { event.error(Errors.INVALID_SAML_AUTHN_REQUEST); event.detail(Details.REASON, "unsupported_nameid_format"); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNSUPPORTED_NAME_ID_FORMAT); + return ErrorPage.error(session, Messages.UNSUPPORTED_NAME_ID_FORMAT); } } @@ -283,7 +285,7 @@ public class SamlService { HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate(headers); if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse(); - LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers) + LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class) .setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode()); // Attach state from SPNEGO authentication @@ -335,7 +337,7 @@ public class SamlService { if (!uriInfo.getAbsolutePath().equals(logoutRequest.getDestination())) { event.error(Errors.INVALID_SAML_LOGOUT_REQUEST); event.detail(Details.REASON, "invalid_destination"); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST); + return ErrorPage.error(session, Messages.INVALID_REQUEST); } // authenticate identity cookie, but ignore an access token timeout as we're logging out anyways. @@ -374,7 +376,7 @@ public class SamlService { if (redirectUri != null) { redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client); if (redirectUri == null) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI ); + return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI); } } if (redirectUri != null) { diff --git a/server/src/main/resources/META-INF/keycloak-server.json b/server/src/main/resources/META-INF/keycloak-server.json index 1f92932ffb..1d7b17f0fa 100755 --- a/server/src/main/resources/META-INF/keycloak-server.json +++ b/server/src/main/resources/META-INF/keycloak-server.json @@ -14,6 +14,13 @@ } }, + "eventsListener": { + "jboss-logging" : { + "success-level": "debug", + "error-level": "warn" + } + }, + "realm": { "provider": "jpa" }, diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java index 6c327b1a67..666586f55f 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java @@ -18,7 +18,6 @@ import org.keycloak.protocol.oidc.endpoints.ValidateTokenEndpoint; import org.keycloak.protocol.oidc.representations.JSONWebKeySet; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.services.resources.flows.Flows; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -204,7 +203,7 @@ public class OIDCLoginProtocolService { @Path("oauth/oob") @GET public Response installedAppUrnCallback(final @QueryParam("code") String code, final @QueryParam("error") String error, final @QueryParam("error_description") String errorDescription) { - LoginFormsProvider forms = Flows.forms(session, realm, null, uriInfo, headers); + LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class); if (code != null) { return forms.setClientSessionCode(code).createCode(); } else { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java index 6cf2d50afc..80aee4ab2a 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java @@ -1,18 +1,17 @@ package org.keycloak.protocol.oidc; import org.keycloak.OAuth2Constants; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.wellknown.WellKnownProvider; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; /** * @author Stian Thorgersen @@ -29,8 +28,17 @@ public class OIDCWellKnownProvider implements WellKnownProvider { public static final List DEFAULT_RESPONSE_MODES_SUPPORTED = list("query"); + private KeycloakSession session; + + public OIDCWellKnownProvider(KeycloakSession session) { + this.session = session; + } + @Override - public Object getConfig(RealmModel realm, UriInfo uriInfo) { + public Object getConfig() { + UriInfo uriInfo = session.getContext().getUri(); + RealmModel realm = session.getContext().getRealm(); + UriBuilder uriBuilder = RealmsResource.protocolUrl(uriInfo); OIDCConfigurationRepresentation config = new OIDCConfigurationRepresentation(); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java index e49a993c55..cf913f1db6 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java @@ -11,16 +11,13 @@ import org.keycloak.wellknown.WellKnownProviderFactory; */ public class OIDCWellKnownProviderFactory implements WellKnownProviderFactory { - private WellKnownProvider provider; - @Override public WellKnownProvider create(KeycloakSession session) { - return provider; + return new OIDCWellKnownProvider(session); } @Override public void init(Config.Scope config) { - provider = new OIDCWellKnownProvider(); } @Override @@ -29,7 +26,6 @@ public class OIDCWellKnownProviderFactory implements WellKnownProviderFactory { @Override public void close() { - provider = null; } @Override diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java index e33cb67f1e..8306b7a520 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java @@ -25,8 +25,7 @@ import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.HttpAuthenticationManager; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.GET; import javax.ws.rs.core.Context; @@ -116,7 +115,7 @@ public class AuthorizationEndpoint { action = Action.REGISTER; if (!realm.isRegistrationAllowed()) { - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED); + throw new ErrorPageException(session, Messages.REGISTRATION_NOT_ALLOWED); } return this; @@ -148,21 +147,21 @@ public class AuthorizationEndpoint { private void checkSsl() { if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) { event.error(Errors.SSL_REQUIRED); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + throw new ErrorPageException(session, Messages.HTTPS_REQUIRED); } } private void checkRealm() { if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + throw new ErrorPageException(session, Messages.REALM_NOT_ENABLED); } } private void checkClient() { if (clientId == null) { event.error(Errors.INVALID_REQUEST); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM ); + throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM ); } event.client(clientId); @@ -170,18 +169,20 @@ public class AuthorizationEndpoint { client = realm.getClientByClientId(clientId); if (client == null) { event.error(Errors.CLIENT_NOT_FOUND); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.CLIENT_NOT_FOUND ); + throw new ErrorPageException(session, Messages.CLIENT_NOT_FOUND ); } if ((client instanceof ClientModel) && ((ClientModel) client).isBearerOnly()) { event.error(Errors.NOT_ALLOWED); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.BEARER_ONLY ); + throw new ErrorPageException(session, Messages.BEARER_ONLY ); } if (client.isDirectGrantsOnly()) { event.error(Errors.NOT_ALLOWED); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.DIRECT_GRANTS_ONLY); + throw new ErrorPageException(session, Messages.DIRECT_GRANTS_ONLY); } + + session.getContext().setClient(client); } private void checkResponseType() { @@ -190,7 +191,7 @@ public class AuthorizationEndpoint { responseType = legacyResponseType; } else { event.error(Errors.INVALID_REQUEST); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM ); + throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM ); } } @@ -200,7 +201,7 @@ public class AuthorizationEndpoint { action = Action.CODE; } else { event.error(Errors.INVALID_REQUEST); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM ); + throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM ); } } @@ -210,7 +211,7 @@ public class AuthorizationEndpoint { redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUriParam, realm, client); if (redirectUri == null) { event.error(Errors.INVALID_REDIRECT_URI); - throw new ErrorPageException(session, realm, uriInfo, headers, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM); + throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM); } } @@ -238,7 +239,7 @@ public class AuthorizationEndpoint { IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(idpHint); if (identityProviderModel == null) { - return Flows.forms(session, realm, null, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(Messages.IDENTITY_PROVIDER_NOT_FOUND, idpHint) .createErrorPage(); } @@ -272,14 +273,13 @@ public class AuthorizationEndpoint { return buildRedirectToIdentityProvider(identityProviders.get(0).getAlias(), accessCode); } - return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.IDENTITY_PROVIDER_NOT_UNIQUE, realm.getName()).createErrorPage(); + return session.getProvider(LoginFormsProvider.class).setError(Messages.IDENTITY_PROVIDER_NOT_UNIQUE, realm.getName()).createErrorPage(); } - return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.REALM_SUPPORTS_NO_CREDENTIALS, realm.getName()).createErrorPage(); + return session.getProvider(LoginFormsProvider.class).setError(Messages.REALM_SUPPORTS_NO_CREDENTIALS, realm.getName()).createErrorPage(); } - LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers) - .setClientSessionCode(accessCode); + LoginFormsProvider forms = session.getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode); // Attach state from SPNEGO authentication if (httpAuthOutput.getChallenge() != null) { @@ -307,7 +307,7 @@ public class AuthorizationEndpoint { private Response buildRegister() { authManager.expireIdentityCookie(realm, uriInfo, clientConnection); - return Flows.forms(session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode()) .createRegistration(); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java index 5bab0e0d11..31cdca3bf2 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java @@ -24,7 +24,7 @@ import org.keycloak.services.ErrorResponseException; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.Cors; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -92,7 +92,7 @@ public class LogoutEndpoint { event.event(EventType.LOGOUT); event.detail(Details.REDIRECT_URI, redirect); event.error(Errors.INVALID_REDIRECT_URI); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI); + return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI); } redirect = validatedUri; } @@ -112,7 +112,7 @@ public class LogoutEndpoint { if (error) { event.event(EventType.LOGOUT); event.error(Errors.INVALID_TOKEN); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE); + return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE); } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index 60b1b98db6..43538eea6d 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -27,7 +27,7 @@ import org.keycloak.services.ErrorResponseException; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.resources.Cors; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.OPTIONS; import javax.ws.rs.POST; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java index ba2f99ceae..f337163c0d 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java @@ -36,7 +36,7 @@ import org.keycloak.representations.AccessToken; import org.keycloak.services.ErrorResponseException; import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.resources.Cors; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java index 249aa30ddb..1e074b8070 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java @@ -15,10 +15,9 @@ import org.keycloak.models.RealmModel; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.representations.AccessToken; import org.keycloak.services.ErrorResponseException; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.GET; -import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.*; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java index 68da8259a3..df650f6c79 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java @@ -4,7 +4,7 @@ import org.jboss.logging.Logger; import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.core.UriInfo; import java.net.URI; diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java new file mode 100644 index 0000000000..1b0e567def --- /dev/null +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java @@ -0,0 +1,50 @@ +package org.keycloak.services; + +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.models.ClientModel; +import org.keycloak.models.KeycloakContext; +import org.keycloak.models.RealmModel; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +/** + * @author Stian Thorgersen + */ +public class DefaultKeycloakContext implements KeycloakContext { + + private RealmModel realm; + + private ClientModel client; + + @Override + public UriInfo getUri() { + return ResteasyProviderFactory.getContextData(UriInfo.class); + } + + @Override + public HttpHeaders getRequestHeaders() { + return ResteasyProviderFactory.getContextData(HttpHeaders.class); + } + + @Override + public RealmModel getRealm() { + return realm; + } + + @Override + public void setRealm(RealmModel realm) { + this.realm = realm; + } + + @Override + public ClientModel getClient() { + return client; + } + + @Override + public void setClient(ClientModel client) { + this.client = client; + } + +} diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java index e83f84d510..190750f2f9 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java @@ -1,5 +1,8 @@ package org.keycloak.services; +import org.jboss.resteasy.spi.HttpRequest; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakTransactionManager; @@ -12,6 +15,7 @@ import org.keycloak.models.cache.CacheUserProvider; import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; +import javax.ws.rs.core.UriInfo; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -32,11 +36,18 @@ public class DefaultKeycloakSession implements KeycloakSession { private UserProvider userModel; private UserSessionProvider sessionProvider; private UserFederationManager federationManager; + private KeycloakContext context; public DefaultKeycloakSession(DefaultKeycloakSessionFactory factory) { this.factory = factory; this.transactionManager = new DefaultKeycloakTransactionManager(); federationManager = new UserFederationManager(this); + context = new DefaultKeycloakContext(); + } + + @Override + public KeycloakContext getContext() { + return context; } private RealmProvider getRealmProvider() { diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java b/services/src/main/java/org/keycloak/services/ErrorPage.java similarity index 60% rename from services/src/main/java/org/keycloak/services/resources/flows/Flows.java rename to services/src/main/java/org/keycloak/services/ErrorPage.java index 3d0697db8a..5f4da73bde 100755 --- a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java +++ b/services/src/main/java/org/keycloak/services/ErrorPage.java @@ -19,35 +19,20 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.keycloak.services.resources.flows; +package org.keycloak.services; import org.keycloak.login.LoginFormsProvider; -import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; /** * @author Stian Thorgersen */ -public class Flows { +public class ErrorPage { - private Flows() { - } - - public static LoginFormsProvider forms(KeycloakSession session, RealmModel realm, ClientModel client, UriInfo uriInfo, HttpHeaders headers) { - return session.getProvider(LoginFormsProvider.class).setRealm(realm).setUriInfo(uriInfo).setClient(client).setHttpHeaders(headers); - } - - public static ErrorFlows errors() { - return new ErrorFlows(); - } - - public static Response forwardToSecurityFailurePage(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String message, Object ... parameters) { - return Flows.forms(session, realm, null, uriInfo, headers).setError(message,parameters).createErrorPage(); + public static Response error(KeycloakSession session, String message, Object... parameters) { + return session.getProvider(LoginFormsProvider.class).setError(message, parameters).createErrorPage(); } diff --git a/services/src/main/java/org/keycloak/services/ErrorPageException.java b/services/src/main/java/org/keycloak/services/ErrorPageException.java index 634ea7a7ac..1b9d0700cc 100644 --- a/services/src/main/java/org/keycloak/services/ErrorPageException.java +++ b/services/src/main/java/org/keycloak/services/ErrorPageException.java @@ -1,13 +1,9 @@ package org.keycloak.services; import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Flows; import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; /** * @author Stian Thorgersen @@ -15,24 +11,18 @@ import javax.ws.rs.core.UriInfo; public class ErrorPageException extends WebApplicationException { private final KeycloakSession session; - private final RealmModel realm; - private final UriInfo uriInfo; - private final HttpHeaders httpHeaders; private final String errorMessage; private final Object[] parameters; - public ErrorPageException(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String errorMessage, Object ... parameters) { + public ErrorPageException(KeycloakSession session, String errorMessage, Object... parameters) { this.session = session; - this.realm = realm; - this.uriInfo = uriInfo; - this.httpHeaders = headers; this.errorMessage = errorMessage; this.parameters = parameters; } @Override public Response getResponse() { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, httpHeaders, errorMessage, parameters); + return ErrorPage.error(session, errorMessage, parameters); } } diff --git a/services/src/main/java/org/keycloak/services/resources/flows/ErrorFlows.java b/services/src/main/java/org/keycloak/services/ErrorResponse.java similarity index 77% rename from services/src/main/java/org/keycloak/services/resources/flows/ErrorFlows.java rename to services/src/main/java/org/keycloak/services/ErrorResponse.java index 7d575d57be..e7539a1259 100755 --- a/services/src/main/java/org/keycloak/services/resources/flows/ErrorFlows.java +++ b/services/src/main/java/org/keycloak/services/ErrorResponse.java @@ -1,4 +1,4 @@ -package org.keycloak.services.resources.flows; +package org.keycloak.services; import org.keycloak.representations.idm.ErrorRepresentation; @@ -8,20 +8,18 @@ import javax.ws.rs.core.Response; /** * @author Stian Thorgersen */ -public class ErrorFlows { +public class ErrorResponse { - public Response exists(String message) { + public static Response exists(String message) { ErrorRepresentation error = new ErrorRepresentation(); error.setErrorMessage(message); return Response.status(Response.Status.CONFLICT).entity(error).type(MediaType.APPLICATION_JSON).build(); } - public Response error(String message, Response.Status status) { + public static Response error(String message, Response.Status status) { ErrorRepresentation error = new ErrorRepresentation(); error.setErrorMessage(message); return Response.status(status).entity(error).type(MediaType.APPLICATION_JSON).build(); } - - } diff --git a/services/src/main/java/org/keycloak/services/ErrorResponseException.java b/services/src/main/java/org/keycloak/services/ErrorResponseException.java index 0dd3e13b8d..6216d58f0f 100644 --- a/services/src/main/java/org/keycloak/services/ErrorResponseException.java +++ b/services/src/main/java/org/keycloak/services/ErrorResponseException.java @@ -1,14 +1,10 @@ package org.keycloak.services; import org.keycloak.OAuth2Constants; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.flows.Flows; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; import java.util.HashMap; import java.util.Map; diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/Urls.java similarity index 99% rename from services/src/main/java/org/keycloak/services/resources/flows/Urls.java rename to services/src/main/java/org/keycloak/services/Urls.java index bb3b0789df..a8cb811534 100755 --- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java +++ b/services/src/main/java/org/keycloak/services/Urls.java @@ -19,7 +19,7 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.keycloak.services.resources.flows; +package org.keycloak.services; import org.keycloak.OAuth2Constants; import org.keycloak.Version; diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 8cd948309b..bd512df819 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -30,8 +30,7 @@ import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.resources.IdentityBrokerService; import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.services.util.CookieHelper; import org.keycloak.services.validation.Validation; import org.keycloak.util.Time; @@ -401,7 +400,7 @@ public class AuthenticationManager { if (action != null) { accessCode.setRequiredAction(action); - LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders()).setClientSessionCode(accessCode.getCode()) + LoginFormsProvider loginFormsProvider = session.getProvider(LoginFormsProvider.class).setClientSessionCode(accessCode.getCode()) .setUser(user); if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) { event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success(); @@ -425,10 +424,9 @@ public class AuthenticationManager { } } - return Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders()) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(accessCode.getCode()) .setAccessRequest(realmRoles, resourceRoles) - .setClient(client) .createOAuthGrant(clientSession); } diff --git a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java index 1cca55cf16..0deb28f699 100755 --- a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java @@ -25,7 +25,7 @@ import org.keycloak.constants.KerberosConstants; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; /** * Handle HTTP authentication types requiring complex handshakes with multiple HTTP request/responses @@ -114,7 +114,7 @@ public class HttpAuthenticationManager { Response response; if (!user.isEnabled()) { event.error(Errors.USER_DISABLED); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.ACCOUNT_DISABLED); + response = ErrorPage.error(session, Messages.ACCOUNT_DISABLED); } else { UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), authMethod, false, null, null); diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 53b460a04c..58f11e9bbc 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -132,6 +132,8 @@ public class RealmManager { realm.setMaxDeltaTimeSeconds(60 * 60 * 12); // 12 hours realm.setFailureFactor(30); realm.setSslRequired(SslRequired.EXTERNAL); + + realm.setEventsListeners(Collections.singleton("jboss-logging")); } public boolean removeRealm(RealmModel realm) { diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index 71fb570adb..3fb84c69ae 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -24,7 +24,9 @@ package org.keycloak.services.resources; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.HttpRequest; +import org.keycloak.AbstractOAuthClient; import org.keycloak.ClientConnection; +import org.keycloak.OAuth2Constants; import org.keycloak.account.AccountPages; import org.keycloak.account.AccountProvider; import org.keycloak.events.Details; @@ -32,6 +34,7 @@ import org.keycloak.events.Event; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventStoreProvider; import org.keycloak.events.EventType; +import org.keycloak.login.LoginFormsProvider; import org.keycloak.models.*; import org.keycloak.models.utils.FormMessage; import org.keycloak.models.utils.ModelToRepresentation; @@ -47,9 +50,7 @@ import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.OAuthRedirect; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.services.util.CookieHelper; import org.keycloak.services.util.ResolveRelative; import org.keycloak.services.validation.Validation; @@ -66,6 +67,7 @@ import javax.ws.rs.core.Cookie; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; @@ -230,7 +232,7 @@ public class AccountService { try { require(AccountRoles.MANAGE_ACCOUNT); } catch (ForbiddenException e) { - return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.NO_ACCESS).createErrorPage(); + return session.getProvider(LoginFormsProvider.class).setError(Messages.NO_ACCESS).createErrorPage(); } setReferrerOnPage(); @@ -873,4 +875,42 @@ public class AccountService { } } + class OAuthRedirect extends AbstractOAuthClient { + + /** + * closes client + */ + public void stop() { + } + + public Response redirect(UriInfo uriInfo, String redirectUri) { + String state = getStateCode(); + + UriBuilder uriBuilder = UriBuilder.fromUri(authUrl) + .queryParam(OAuth2Constants.CLIENT_ID, clientId) + .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri) + .queryParam(OAuth2Constants.STATE, state) + .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE); + if (scope != null) { + uriBuilder.queryParam(OAuth2Constants.SCOPE, scope); + } + + URI url = uriBuilder.build(); + + // todo httpOnly! + NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure); + logger.debug("NewCookie: " + cookie.toString()); + logger.debug("Oauth Redirect to: " + url); + return Response.status(302) + .location(url) + .cookie(cookie).build(); + } + + private String getStateCookiePath(UriInfo uriInfo) { + if (stateCookiePath != null) return stateCookiePath; + return uriInfo.getBaseUri().getRawPath(); + } + + } + } diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index f8e5e8febc..051aa04b5c 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -30,6 +30,7 @@ import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; +import org.keycloak.login.LoginFormsProvider; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; @@ -45,8 +46,9 @@ import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager.AuthResult; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.ErrorResponse; +import org.keycloak.services.ErrorPage; +import org.keycloak.services.Urls; import org.keycloak.services.validation.Validation; import org.keycloak.social.SocialIdentityProvider; import org.keycloak.util.ObjectUtil; @@ -185,15 +187,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal return badRequest("Invalid client."); } + session.getContext().setClient(clientModel); + if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) { return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel); } if (clientModel.isConsentRequired()) { - return corsResponse(Flows.forms(this.session, this.realmModel, clientModel, this.uriInfo, headers) + return corsResponse(session.getProvider(LoginFormsProvider.class) .setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders())) .setAccessRequest("Your information from " + providerId + " identity provider.") - .setClient(clientModel) .setActionUri(this.uriInfo.getRequestUri()) .createOAuthGrant(null), clientModel); } @@ -411,7 +414,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } fireErrorEvent(message, throwable); - return Flows.forwardToSecurityFailurePage(this.session, this.realmModel, this.uriInfo, headers, message, parameters); + return ErrorPage.error(this.session, message, parameters); } private Response redirectToLoginPage(Throwable t, ClientSessionCode clientCode) { @@ -422,7 +425,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } fireErrorEvent(message); - return Flows.forms(this.session, this.realmModel, clientCode.getClientSession().getClient(), this.uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(clientCode.getCode()) .setError(message) .createLogin(); @@ -430,7 +433,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal private Response badRequest(String message) { fireErrorEvent(message); - return Flows.errors().error(message, Status.BAD_REQUEST); + return ErrorResponse.error(message, Status.BAD_REQUEST); } public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) { diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 106be1cadc..f3f5937fc6 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -53,8 +53,8 @@ import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.ErrorPage; +import org.keycloak.services.Urls; import org.keycloak.services.util.CookieHelper; import org.keycloak.services.validation.Validation; @@ -162,7 +162,7 @@ public class LoginActionsService { return false; } else if (!clientCode.isValid(requiredAction)) { event.error(Errors.INVALID_CODE); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_CODE); + response = ErrorPage.error(session, Messages.INVALID_CODE); return false; } else { return true; @@ -174,7 +174,7 @@ public class LoginActionsService { return false; } else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) { event.error(Errors.INVALID_CODE); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo,headers, Messages.INVALID_CODE); + response = ErrorPage.error(session, Messages.INVALID_CODE); return false; } else { return true; @@ -184,20 +184,21 @@ public class LoginActionsService { public boolean check(String code) { if (!checkSsl()) { event.error(Errors.SSL_REQUIRED); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + response = ErrorPage.error(session, Messages.HTTPS_REQUIRED); return false; } if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + response = ErrorPage.error(session, Messages.REALM_NOT_ENABLED); return false; } clientCode = ClientSessionCode.parse(code, session, realm); if (clientCode == null) { event.error(Errors.INVALID_CODE); - response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE); + response = ErrorPage.error(session, Messages.UNKNOWN_CODE); return false; } + session.getContext().setClient(clientCode.getClientSession().getClient()); return true; } } @@ -226,10 +227,9 @@ public class LoginActionsService { clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE); } - LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers) - .setClientSessionCode(clientSessionCode.getCode()); - - return forms.createLogin(); + return session.getProvider(LoginFormsProvider.class) + .setClientSessionCode(clientSessionCode.getCode()) + .createLogin(); } /** @@ -244,7 +244,7 @@ public class LoginActionsService { event.event(EventType.REGISTER); if (!realm.isRegistrationAllowed()) { event.error(Errors.REGISTRATION_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED); + return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED); } Checks checks = new Checks(); @@ -258,7 +258,7 @@ public class LoginActionsService { authManager.expireIdentityCookie(realm, uriInfo, clientConnection); - return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(clientSessionCode.getCode()) .createRegistration(); } @@ -278,17 +278,17 @@ public class LoginActionsService { event.event(EventType.LOGIN); if (!checkSsl()) { event.error(Errors.SSL_REQUIRED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + return ErrorPage.error(session, Messages.REALM_NOT_ENABLED); } ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm); if (clientCode == null) { event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE); + return ErrorPage.error(session, Messages.UNKNOWN_CODE); } ClientSessionModel clientSession = clientCode.getClientSession(); @@ -297,7 +297,8 @@ public class LoginActionsService { if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) { clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE); event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE); - return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo, headers).setError(Messages.EXPIRED_CODE) + return session.getProvider(LoginFormsProvider.class) + .setError(Messages.EXPIRED_CODE) .setClientSessionCode(clientCode.getCode()) .createLogin(); } @@ -320,13 +321,15 @@ public class LoginActionsService { ClientModel client = clientSession.getClient(); if (client == null) { event.error(Errors.CLIENT_NOT_FOUND); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER); + return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER); } if (!client.isEnabled()) { event.error(Errors.CLIENT_NOT_FOUND); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED); + return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED); } + session.getContext().setClient(clientSession.getClient()); + if (formData.containsKey("cancel")) { event.error(Errors.REJECTED_BY_USER); LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod()); @@ -358,14 +361,14 @@ public class LoginActionsService { return authManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event); case ACCOUNT_TEMPORARILY_DISABLED: event.error(Errors.USER_TEMPORARILY_DISABLED); - return Flows.forms(this.session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(Messages.ACCOUNT_TEMPORARILY_DISABLED) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) .createLogin(); case ACCOUNT_DISABLED: event.error(Errors.USER_DISABLED); - return Flows.forms(this.session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(Messages.ACCOUNT_DISABLED) .setClientSessionCode(clientCode.getCode()) .setFormData(formData).createLogin(); @@ -375,19 +378,21 @@ public class LoginActionsService { String passwordToken = new JWSBuilder().jsonContent(new PasswordToken(realm.getName(), user.getId())).rsa256(realm.getPrivateKey()); formData.add(CredentialRepresentation.PASSWORD_TOKEN, passwordToken); - return Flows.forms(this.session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) .createLoginTotp(); case INVALID_USER: event.error(Errors.USER_NOT_FOUND); - return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.INVALID_USER) + return session.getProvider(LoginFormsProvider.class) + .setError(Messages.INVALID_USER) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) .createLogin(); default: event.error(Errors.INVALID_USER_CREDENTIALS); - return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.INVALID_USER) + return session.getProvider(LoginFormsProvider.class) + .setError(Messages.INVALID_USER) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) .createLogin(); @@ -409,25 +414,25 @@ public class LoginActionsService { event.event(EventType.REGISTER); if (!checkSsl()) { event.error(Errors.SSL_REQUIRED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + return ErrorPage.error(session, Messages.REALM_NOT_ENABLED); } if (!realm.isRegistrationAllowed()) { event.error(Errors.REGISTRATION_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED); + return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED); } ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm); if (clientCode == null) { event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE); + return ErrorPage.error(session, Messages.UNKNOWN_CODE); } if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE)) { event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_CODE); + return ErrorPage.error(session, Messages.INVALID_CODE); } String username = formData.getFirst(Validation.FIELD_USERNAME); @@ -446,19 +451,20 @@ public class LoginActionsService { if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + return ErrorPage.error(session, Messages.REALM_NOT_ENABLED); } ClientModel client = clientSession.getClient(); if (client == null) { event.error(Errors.CLIENT_NOT_FOUND); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER); + return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER); } if (!client.isEnabled()) { event.error(Errors.CLIENT_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED); + return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED); } + session.getContext().setClient(client); List requiredCredentialTypes = new LinkedList(); for (RequiredCredentialModel m : realm.getRequiredCredentials()) { @@ -470,7 +476,7 @@ public class LoginActionsService { if (errors != null && !errors.isEmpty()) { event.error(Errors.INVALID_REGISTRATION); - return Flows.forms(session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setErrors(errors) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) @@ -480,7 +486,7 @@ public class LoginActionsService { // Validate that user with this username doesn't exist in realm or any federation provider if (session.users().getUserByUsername(username, realm) != null) { event.error(Errors.USERNAME_IN_USE); - return Flows.forms(session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(Messages.USERNAME_EXISTS) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) @@ -490,7 +496,7 @@ public class LoginActionsService { // Validate that user with this email doesn't exist in realm or any federation provider if (email != null && session.users().getUserByEmail(email, realm) != null) { event.error(Errors.EMAIL_IN_USE); - return Flows.forms(session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(Messages.EMAIL_EXISTS) .setFormData(formData) .setClientSessionCode(clientCode.getCode()) @@ -527,7 +533,7 @@ public class LoginActionsService { // User already registered, but force him to update password if (!passwordUpdateSuccessful) { user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); - return Flows.forms(session, realm, client, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setError(passwordUpdateError, passwordUpdateErrorParameters) .setClientSessionCode(clientCode.getCode()) .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD); @@ -556,7 +562,7 @@ public class LoginActionsService { if (!checkSsl()) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } String code = formData.getFirst("code"); @@ -564,7 +570,7 @@ public class LoginActionsService { ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm); if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT)) { event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_ACCESS_CODE); + return ErrorPage.error(session, Messages.INVALID_ACCESS_CODE); } ClientSessionModel clientSession = accessCode.getClientSession(); event.detail(Details.CODE_ID, clientSession.getId()); @@ -588,7 +594,7 @@ public class LoginActionsService { if (!AuthenticationManager.isSessionValid(realm, userSession)) { AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, clientConnection, headers); event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE); + return ErrorPage.error(session, Messages.SESSION_NOT_ACTIVE); } event.session(userSession); @@ -625,8 +631,10 @@ public class LoginActionsService { List errors = Validation.validateUpdateProfileForm(formData); if (errors != null && !errors.isEmpty()) { - return Flows.forms(session, realm, null, uriInfo, headers).setUser(user).setErrors(errors) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(accessCode.getCode()) + .setUser(user) + .setErrors(errors) .createResponse(RequiredAction.UPDATE_PROFILE); } @@ -643,7 +651,9 @@ public class LoginActionsService { // check for duplicated email if (userByEmail != null && !userByEmail.getId().equals(user.getId())) { - return Flows.forms(session, realm, null, uriInfo, headers).setUser(user).setError(Messages.EMAIL_EXISTS) + return session.getProvider(LoginFormsProvider.class) + .setUser(user) + .setError(Messages.EMAIL_EXISTS) .setClientSessionCode(accessCode.getCode()) .createResponse(RequiredAction.UPDATE_PROFILE); } @@ -682,7 +692,7 @@ public class LoginActionsService { String totp = formData.getFirst("totp"); String totpSecret = formData.getFirst("totpSecret"); - LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo, headers).setUser(user); + LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class).setUser(user); if (Validation.isEmpty(totp)) { return loginForms.setError(Messages.MISSING_TOTP) .setClientSessionCode(accessCode.getCode()) @@ -727,7 +737,8 @@ public class LoginActionsService { String passwordNew = formData.getFirst("password-new"); String passwordConfirm = formData.getFirst("password-confirm"); - LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo, headers).setUser(user); + LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class) + .setUser(user); if (Validation.isEmpty(passwordNew)) { return loginForms.setError(Messages.MISSING_PASSWORD) .setClientSessionCode(accessCode.getCode()) @@ -757,7 +768,9 @@ public class LoginActionsService { if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) { String actionCookieValue = getActionCookie(); if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) { - return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers).setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED).createInfoPage(); + return session.getProvider(LoginFormsProvider.class) + .setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED) + .createInfoPage(); } } @@ -789,7 +802,9 @@ public class LoginActionsService { String actionCookieValue = getActionCookie(); if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) { - return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers).setSuccess(Messages.EMAIL_VERIFIED).createInfoPage(); + return session.getProvider(LoginFormsProvider.class) + .setSuccess(Messages.EMAIL_VERIFIED) + .createInfoPage(); } event = event.clone().removeDetail(Details.EMAIL).event(EventType.LOGIN); @@ -807,7 +822,7 @@ public class LoginActionsService { createActionCookie(realm, uriInfo, clientConnection, userSession.getId()); - return Flows.forms(session, realm, null, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(accessCode.getCode()) .setUser(userSession.getUser()) .createResponse(RequiredAction.VERIFY_EMAIL); @@ -824,11 +839,11 @@ public class LoginActionsService { return checks.response; } ClientSessionCode accessCode = checks.clientCode; - return Flows.forms(session, realm, null, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(accessCode.getCode()) .createResponse(RequiredAction.UPDATE_PASSWORD); } else { - return Flows.forms(session, realm, null, uriInfo, headers) + return session.getProvider(LoginFormsProvider.class) .setClientSessionCode(code) .createPasswordReset(); } @@ -841,16 +856,16 @@ public class LoginActionsService { final MultivaluedMap formData) { event.event(EventType.SEND_RESET_PASSWORD); if (!checkSsl()) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED); + return ErrorPage.error(session, Messages.HTTPS_REQUIRED); } if (!realm.isEnabled()) { event.error(Errors.REALM_DISABLED); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED); + return ErrorPage.error(session, Messages.REALM_NOT_ENABLED); } ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm); if (accessCode == null) { event.error(Errors.INVALID_CODE); - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE); + return ErrorPage.error(session, Messages.UNKNOWN_CODE); } ClientSessionModel clientSession = accessCode.getClientSession(); @@ -858,12 +873,14 @@ public class LoginActionsService { ClientModel client = clientSession.getClient(); if (client == null) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER); + return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER); } if (!client.isEnabled()) { - return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED); + return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED); } + session.getContext().setClient(client); + event.client(client.getClientId()) .detail(Details.REDIRECT_URI, clientSession.getRedirectUri()) .detail(Details.RESPONSE_TYPE, "code") @@ -904,7 +921,8 @@ public class LoginActionsService { } catch (EmailException e) { event.error(Errors.EMAIL_SEND_FAILED); logger.error("Failed to send password reset email", e); - return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.EMAIL_SENT_ERROR) + return session.getProvider(LoginFormsProvider.class) + .setError(Messages.EMAIL_SENT_ERROR) .setClientSessionCode(accessCode.getCode()) .createErrorPage(); } @@ -912,7 +930,10 @@ public class LoginActionsService { createActionCookie(realm, uriInfo, clientConnection, userSession.getId()); } - return Flows.forms(session, realm, client, uriInfo, headers).setSuccess(Messages.EMAIL_SENT).setClientSessionCode(accessCode.getCode()).createPasswordReset(); + return session.getProvider(LoginFormsProvider.class) + .setSuccess(Messages.EMAIL_SENT) + .setClientSessionCode(accessCode.getCode()) + .createPasswordReset(); } private String getActionCookie() { diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java index 571f111a8f..b3dd57044b 100755 --- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java @@ -24,7 +24,6 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; @@ -38,17 +37,6 @@ import javax.ws.rs.core.UriInfo; public class RealmsResource { protected static Logger logger = Logger.getLogger(RealmsResource.class); - @Context - protected UriInfo uriInfo; - - @Context - protected HttpHeaders headers; - - /* - @Context - protected ResourceContext resourceContext; - */ - @Context protected KeycloakSession session; @@ -62,18 +50,10 @@ public class RealmsResource { return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getRealmResource"); } - public static UriBuilder realmBaseUrl(UriBuilder base) { - return base.path(RealmsResource.class).path(RealmsResource.class, "getRealmResource"); - } - public static UriBuilder accountUrl(UriBuilder base) { return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService"); } - public static UriBuilder protocolUrl(UriBuilder base) { - return base.path(RealmsResource.class).path(RealmsResource.class, "getProtocol"); - } - public static UriBuilder protocolUrl(UriInfo uriInfo) { return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getProtocol"); } @@ -87,9 +67,8 @@ public class RealmsResource { public Object getLoginStatusIframe(final @PathParam("realm") String name, @QueryParam("client_id") String client_id, @QueryParam("origin") String origin) { - // backward compatibility - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); + EventBuilder event = new EventBuilder(realm, session, clientConnection); AuthenticationManager authManager = new AuthenticationManager(protector); @@ -104,8 +83,8 @@ public class RealmsResource { @Path("{realm}/protocol/{protocol}") public Object getProtocol(final @PathParam("realm") String name, final @PathParam("protocol") String protocol) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); + EventBuilder event = new EventBuilder(realm, session, clientConnection); AuthenticationManager authManager = new AuthenticationManager(protector); @@ -125,8 +104,7 @@ public class RealmsResource { @Path("{realm}/login-actions") public LoginActionsService getLoginActionsService(final @PathParam("realm") String name) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); EventBuilder event = new EventBuilder(realm, session, clientConnection); AuthenticationManager authManager = new AuthenticationManager(protector); LoginActionsService service = new LoginActionsService(realm, authManager, event); @@ -136,26 +114,26 @@ public class RealmsResource { @Path("{realm}/clients-managements") public ClientsManagementService getClientsManagementService(final @PathParam("realm") String name) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); EventBuilder event = new EventBuilder(realm, session, clientConnection); ClientsManagementService service = new ClientsManagementService(realm, event); ResteasyProviderFactory.getInstance().injectProperties(service); return service; } - protected RealmModel locateRealm(String name, RealmManager realmManager) { - RealmModel realm = realmManager.getRealmByName(name); + private RealmModel init(String realmName) { + RealmManager realmManager = new RealmManager(session); + RealmModel realm = realmManager.getRealmByName(realmName); if (realm == null) { throw new NotFoundException("Realm does not exist"); } + session.getContext().setRealm(realm); return realm; } @Path("{realm}/account") public AccountService getAccountService(final @PathParam("realm") String name) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); ClientModel client = realm.getClientNameMap().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); if (client == null || !client.isEnabled()) { @@ -172,8 +150,7 @@ public class RealmsResource { @Path("{realm}") public PublicRealmResource getRealmResource(final @PathParam("realm") String name) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); PublicRealmResource realmResource = new PublicRealmResource(realm); ResteasyProviderFactory.getInstance().injectProperties(realmResource); return realmResource; @@ -181,8 +158,7 @@ public class RealmsResource { @Path("{realm}/broker") public IdentityBrokerService getBrokerService(final @PathParam("realm") String name) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(name, realmManager); + RealmModel realm = init(name); IdentityBrokerService brokerService = new IdentityBrokerService(realm); ResteasyProviderFactory.getInstance().injectProperties(brokerService); @@ -195,12 +171,12 @@ public class RealmsResource { @GET @Path("{realm}/.well-known/{provider}") @Produces(MediaType.APPLICATION_JSON) - public Response getWellKnown(final @PathParam("realm") String realmName, + public Response getWellKnown(final @PathParam("realm") String name, final @PathParam("provider") String providerName) { - RealmManager realmManager = new RealmManager(session); - RealmModel realm = locateRealm(realmName, realmManager); + init(name); + WellKnownProvider wellKnown = session.getProvider(WellKnownProvider.class, providerName); - return Response.ok(wellKnown.getConfig(realm, uriInfo)).build(); + return Response.ok(wellKnown.getConfig()).build(); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java index 24d76b2873..e8c5447a95 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java @@ -26,7 +26,7 @@ import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.KeycloakApplication; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import javax.ws.rs.GET; import javax.ws.rs.Path; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java index f0decf37fe..98eb743a4f 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java @@ -23,7 +23,7 @@ import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.resources.KeycloakApplication; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import org.keycloak.util.JsonSerialization; import org.keycloak.util.Time; @@ -100,7 +100,7 @@ public class ClientResource { RepresentationToModel.updateClient(rep, client); return Response.noContent().build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Client " + rep.getClientId() + " already exists"); + return ErrorResponse.exists("Client " + rep.getClientId() + " already exists"); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java index 270b7ac4e4..b68bfc79f2 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java @@ -11,7 +11,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -91,7 +91,7 @@ public class ClientsResource { ClientModel clientModel = RepresentationToModel.createClient(session, realm, rep, true); return Response.created(uriInfo.getAbsolutePathBuilder().path(getClientPath(clientModel)).build()).build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Client " + rep.getClientId() + " already exists"); + return ErrorResponse.exists("Client " + rep.getClientId() + " already exists"); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java index bbb32b441b..fc8734380b 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java @@ -16,7 +16,7 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.provider.ProviderFactory; import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import org.keycloak.social.SocialIdentityProvider; import javax.ws.rs.Consumes; @@ -96,7 +96,7 @@ public class IdentityProviderResource { return Response.noContent().build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Identity Provider " + providerRep.getAlias() + " already exists"); + return ErrorResponse.exists("Identity Provider " + providerRep.getAlias() + " already exists"); } } @@ -169,7 +169,7 @@ public class IdentityProviderResource { IdentityProviderFactory factory = getIdentityProviderFactory(); return factory.create(identityProviderModel).export(uriInfo, realm, format); } catch (Exception e) { - return Flows.errors().error("Could not export public broker configuration for identity provider [" + identityProviderModel.getProviderId() + "].", Response.Status.NOT_FOUND); + return ErrorResponse.error("Could not export public broker configuration for identity provider [" + identityProviderModel.getProviderId() + "].", Response.Status.NOT_FOUND); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java index ef0e94bd25..34cdc784b0 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java @@ -17,7 +17,7 @@ import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.provider.ProviderFactory; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.services.managers.ResourceAdminManager; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import org.keycloak.social.SocialIdentityProvider; import javax.ws.rs.Consumes; @@ -132,7 +132,7 @@ public class IdentityProvidersResource { return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Identity Provider " + representation.getAlias() + " already exists"); + return ErrorResponse.exists("Identity Provider " + representation.getAlias() + " already exists"); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 5fea57dfbf..6031c2eb96 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -29,7 +29,7 @@ import org.keycloak.services.managers.LDAPConnectionTestManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.UsersSyncManager; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import org.keycloak.timer.TimerProvider; import javax.ws.rs.Consumes; @@ -191,11 +191,11 @@ public class RealmAdminResource { return Response.noContent().build(); } catch (PatternSyntaxException e) { - return Flows.errors().exists("Specified regex pattern(s) is invalid."); + return ErrorResponse.exists("Specified regex pattern(s) is invalid."); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Realm " + rep.getRealm() + " already exists."); + return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists."); } catch (Exception e) { - return Flows.errors().exists("Failed to update " + rep.getRealm() + " Realm."); + return ErrorResponse.exists("Failed to update " + rep.getRealm() + " Realm."); } } @@ -442,7 +442,7 @@ public class RealmAdminResource { auth.init(RealmAuth.Resource.REALM).requireManage(); boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential); - return result ? Response.noContent().build() : Flows.errors().error("LDAP test error", Response.Status.BAD_REQUEST); + return result ? Response.noContent().build() : ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST); } @Path("identity-provider") diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java index 21fc79e952..c9fea3d09d 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java @@ -18,7 +18,7 @@ import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.services.ForbiddenException; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.resources.KeycloakApplication; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import org.keycloak.util.JsonSerialization; import javax.ws.rs.Consumes; @@ -131,7 +131,7 @@ public class RealmsAdminResource { return Response.created(location).build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Realm " + rep.getRealm() + " already exists"); + return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists"); } } @@ -166,7 +166,7 @@ public class RealmsAdminResource { try { realm = realmManager.importRealm(rep); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Realm " + rep.getRealm() + " already exists"); + return ErrorResponse.exists("Realm " + rep.getRealm() + " already exists"); } grantPermissionsToRealmCreator(realm); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java index 66d37a9492..fa0064fca7 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java @@ -9,7 +9,7 @@ import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorResponse; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -79,7 +79,7 @@ public class RoleContainerResource extends RoleResource { role.setDescription(rep.getDescription()); return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Role with name " + rep.getName() + " already exists"); + return ErrorResponse.exists("Role with name " + rep.getName() + " already exists"); } } @@ -144,7 +144,7 @@ public class RoleContainerResource extends RoleResource { updateRole(rep, role); return Response.noContent().build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("Role with name " + rep.getName() + " already exists"); + return ErrorResponse.exists("Role with name " + rep.getName() + " already exists"); } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java index bbf202cd82..a1dd22d5c3 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java @@ -36,8 +36,8 @@ import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.UserManager; -import org.keycloak.services.resources.flows.Flows; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.ErrorResponse; +import org.keycloak.services.Urls; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -123,9 +123,9 @@ public class UsersResource { return Response.noContent().build(); } catch (ModelDuplicateException e) { - return Flows.errors().exists("User exists with same username or email"); + return ErrorResponse.exists("User exists with same username or email"); } catch (ModelReadOnlyException re) { - return Flows.errors().exists("User is read only!"); + return ErrorResponse.exists("User is read only!"); } } @@ -143,10 +143,10 @@ public class UsersResource { // Double-check duplicated username and email here due to federation if (session.users().getUserByUsername(rep.getUsername(), realm) != null) { - return Flows.errors().exists("User exists with same username"); + return ErrorResponse.exists("User exists with same username"); } if (rep.getEmail() != null && session.users().getUserByEmail(rep.getEmail(), realm) != null) { - return Flows.errors().exists("User exists with same email"); + return ErrorResponse.exists("User exists with same email"); } try { @@ -162,7 +162,7 @@ public class UsersResource { if (session.getTransaction().isActive()) { session.getTransaction().setRollbackOnly(); } - return Flows.errors().exists("User exists with same username or email"); + return ErrorResponse.exists("User exists with same username or email"); } } @@ -287,7 +287,7 @@ public class UsersResource { throw new NotFoundException("User not found"); } if (session.users().getFederatedIdentity(user, provider, realm) != null) { - return Flows.errors().exists("User is already linked with provider"); + return ErrorResponse.exists("User is already linked with provider"); } FederatedIdentityModel socialLink = new FederatedIdentityModel(provider, rep.getUserId(), rep.getUserName()); @@ -352,7 +352,7 @@ public class UsersResource { if (removed) { return Response.noContent().build(); } else { - return Flows.errors().error("User couldn't be deleted", Response.Status.BAD_REQUEST); + return ErrorResponse.error("User couldn't be deleted", Response.Status.BAD_REQUEST); } } @@ -702,19 +702,19 @@ public class UsersResource { UserModel user = session.users().getUserByUsername(username, realm); if (user == null) { - return Flows.errors().error("User not found", Response.Status.NOT_FOUND); + return ErrorResponse.error("User not found", Response.Status.NOT_FOUND); } if (!user.isEnabled()) { - return Flows.errors().error("User is disabled", Response.Status.BAD_REQUEST); + return ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST); } if (user.getEmail() == null) { - return Flows.errors().error("User email missing", Response.Status.BAD_REQUEST); + return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST); } if(redirectUri != null && clientId == null){ - return Flows.errors().error("Client id missing", Response.Status.BAD_REQUEST); + return ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST); } if(clientId == null){ @@ -723,14 +723,14 @@ public class UsersResource { ClientModel client = realm.getClientByClientId(clientId); if (client == null || !client.isEnabled()) { - return Flows.errors().error(clientId + " not enabled", Response.Status.INTERNAL_SERVER_ERROR); + return ErrorResponse.error(clientId + " not enabled", Response.Status.INTERNAL_SERVER_ERROR); } String redirect; if(redirectUri != null){ redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client); if(redirect == null){ - return Flows.errors().error("Invalid redirect uri.", Response.Status.BAD_REQUEST); + return ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST); } }else{ redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString(); @@ -760,7 +760,7 @@ public class UsersResource { return Response.ok().build(); } catch (EmailException e) { logger.error("Failed to send password reset email", e); - return Flows.errors().error("Failed to send email", Response.Status.INTERNAL_SERVER_ERROR); + return ErrorResponse.error("Failed to send email", Response.Status.INTERNAL_SERVER_ERROR); } } diff --git a/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java b/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java deleted file mode 100755 index 2ccb4a004a..0000000000 --- a/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.keycloak.services.resources.flows; - -import org.jboss.logging.Logger; -import org.jboss.resteasy.spi.BadRequestException; -import org.keycloak.AbstractOAuthClient; -import org.keycloak.OAuth2Constants; - -import javax.ws.rs.core.Cookie; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.NewCookie; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; -import java.net.URI; - -/** - * Helper code to obtain oauth access tokens via browser redirects - * - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class OAuthRedirect extends AbstractOAuthClient { - protected static final Logger logger = Logger.getLogger(OAuthRedirect.class); - - /** - * closes client - */ - public void stop() { - } - - public Response redirect(UriInfo uriInfo, String redirectUri) { - String state = getStateCode(); - - UriBuilder uriBuilder = UriBuilder.fromUri(authUrl) - .queryParam(OAuth2Constants.CLIENT_ID, clientId) - .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri) - .queryParam(OAuth2Constants.STATE, state) - .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE); - if (scope != null) { - uriBuilder.queryParam(OAuth2Constants.SCOPE, scope); - } - - URI url = uriBuilder.build(); - - // todo httpOnly! - NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure); - logger.debug("NewCookie: " + cookie.toString()); - logger.debug("Oauth Redirect to: " + url); - return Response.status(302) - .location(url) - .cookie(cookie).build(); - } - - public String getStateCookiePath(UriInfo uriInfo) { - if (stateCookiePath != null) return stateCookiePath; - return uriInfo.getBaseUri().getRawPath(); - } - - public String getError(UriInfo uriInfo) { - return uriInfo.getQueryParameters().getFirst(OAuth2Constants.ERROR); - } - - public String getAccessCode(UriInfo uriInfo) { - return uriInfo.getQueryParameters().getFirst(OAuth2Constants.CODE); - } - - public void checkStateCookie(UriInfo uriInfo, HttpHeaders headers) { - Cookie stateCookie = headers.getCookies().get(stateCookieName); - if (stateCookie == null) throw new BadRequestException("state cookie not set"); - String state = uriInfo.getQueryParameters().getFirst(OAuth2Constants.STATE); - if (state == null) throw new BadRequestException("state parameter was null"); - if (!state.equals(stateCookie.getValue())) { - throw new BadRequestException("state parameter invalid"); - } - } -} diff --git a/services/src/main/java/org/keycloak/wellknown/WellKnownProvider.java b/services/src/main/java/org/keycloak/wellknown/WellKnownProvider.java index d4b80d7795..ed9021f553 100755 --- a/services/src/main/java/org/keycloak/wellknown/WellKnownProvider.java +++ b/services/src/main/java/org/keycloak/wellknown/WellKnownProvider.java @@ -1,16 +1,12 @@ package org.keycloak.wellknown; -import org.keycloak.models.RealmModel; import org.keycloak.provider.Provider; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - /** * @author Stian Thorgersen */ public interface WellKnownProvider extends Provider { - Object getConfig(RealmModel realm, UriInfo uriInfo); + Object getConfig(); } diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java index fea19e9ded..9d1d411503 100755 --- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java +++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java @@ -37,7 +37,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; -import org.keycloak.services.resources.flows.Flows; +import org.keycloak.services.ErrorPage; import org.keycloak.social.SocialIdentityProvider; import twitter4j.Twitter; import twitter4j.TwitterFactory; @@ -158,7 +158,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProviderkeycloak-admin-client ${project.version} + + org.keycloak + event-listener-sysout-example + ${project.version} + log4j log4j diff --git a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json index 188db1e12e..2c56c58f53 100755 --- a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json +++ b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json @@ -7,6 +7,13 @@ "provider": "${keycloak.eventStore.provider:jpa}" }, + "eventsListener": { + "jboss-logging" : { + "success-level": "debug", + "error-level": "warn" + } + }, + "realm": { "provider": "${keycloak.realm.provider:jpa}" }, diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties index cfd1259474..d94d2f9c74 100755 --- a/testsuite/integration/src/main/resources/log4j.properties +++ b/testsuite/integration/src/main/resources/log4j.properties @@ -6,6 +6,9 @@ log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n log4j.logger.org.keycloak=info +# Enable to view events +# log4j.logger.org.keycloak.events=debug + # Enable to view loaded SPI and Providers # log4j.logger.org.keycloak.services.DefaultKeycloakSessionFactory=debug # log4j.logger.org.keycloak.provider.ProviderManager=debug diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java index 9026ebc16d..ea06aac693 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java @@ -38,7 +38,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.representations.IDToken; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient.AccessTokenResponse; import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java index 2e3556efd3..4c0279848f 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java @@ -2,7 +2,7 @@ package org.keycloak.testsuite.pages; import javax.ws.rs.core.UriBuilder; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.testsuite.Constants; import org.openqa.selenium.By; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountLogPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountLogPage.java index 846b526326..2a7c307be2 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountLogPage.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountLogPage.java @@ -21,7 +21,7 @@ */ package org.keycloak.testsuite.pages; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.testsuite.Constants; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountSessionsPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountSessionsPage.java index 5467a48aff..bfadc6d339 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountSessionsPage.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountSessionsPage.java @@ -21,7 +21,7 @@ */ package org.keycloak.testsuite.pages; -import org.keycloak.services.resources.flows.Urls; +import org.keycloak.services.Urls; import org.keycloak.testsuite.Constants; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java index 1f0b7a25de..2be207c5c8 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java @@ -103,11 +103,6 @@ public class LoginPage extends AbstractPage { return loginErrorMessage != null ? loginErrorMessage.getText() : null; } - public String getWarning() { - return loginWarningMessage != null ? loginWarningMessage.getText() : null; - } - - public boolean isCurrent() { return driver.getTitle().equals("Log in to test") || driver.getTitle().equals("Anmeldung bei test"); }