/* * Copyright 2017 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.keycloak.authentication.actiontoken; import org.keycloak.OAuth2Constants; import org.keycloak.authentication.AuthenticationProcessor; import org.keycloak.common.ClientConnection; import org.keycloak.events.EventBuilder; import org.keycloak.models.*; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.JsonWebToken; import org.keycloak.services.Urls; import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.sessions.AuthenticationSessionModel; import java.util.function.Function; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilderException; import javax.ws.rs.core.UriInfo; import org.jboss.resteasy.spi.HttpRequest; /** * * @author hmlnarik */ public class ActionTokenContext<T extends JsonWebToken> { @FunctionalInterface public interface ProcessAuthenticateFlow { Response processFlow(boolean action, String execution, AuthenticationSessionModel authSession, String flowPath, AuthenticationFlowModel flow, String errorMessage, AuthenticationProcessor processor); }; @FunctionalInterface public interface ProcessBrokerFlow { Response brokerLoginFlow(String code, String execution, String flowPath); }; private final KeycloakSession session; private final RealmModel realm; private final UriInfo uriInfo; private final ClientConnection clientConnection; private final HttpRequest request; private EventBuilder event; private final ActionTokenHandler<T> handler; private AuthenticationSessionModel authenticationSession; private boolean authenticationSessionFresh; private String executionId; private final ProcessAuthenticateFlow processAuthenticateFlow; private final ProcessBrokerFlow processBrokerFlow; public ActionTokenContext(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection clientConnection, HttpRequest request, EventBuilder event, ActionTokenHandler<T> handler, String executionId, ProcessAuthenticateFlow processFlow, ProcessBrokerFlow processBrokerFlow) { this.session = session; this.realm = realm; this.uriInfo = uriInfo; this.clientConnection = clientConnection; this.request = request; this.event = event; this.handler = handler; this.executionId = executionId; this.processAuthenticateFlow = processFlow; this.processBrokerFlow = processBrokerFlow; } public EventBuilder getEvent() { return event; } public void setEvent(EventBuilder event) { this.event = event; } public KeycloakSession getSession() { return session; } public RealmModel getRealm() { return realm; } public UriInfo getUriInfo() { return uriInfo; } public ClientConnection getClientConnection() { return clientConnection; } public HttpRequest getRequest() { return request; } public AuthenticationSessionModel createAuthenticationSessionForClient(String clientId) throws UriBuilderException, IllegalArgumentException { AuthenticationSessionModel authSession; // set up the account service as the endpoint to call. ClientModel client = realm.getClientByClientId(clientId == null ? Constants.ACCOUNT_MANAGEMENT_CLIENT_ID : clientId); authSession = new AuthenticationSessionManager(session).createAuthenticationSession(realm, client, true); authSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name()); authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); String redirectUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString(); authSession.setRedirectUri(redirectUri); authSession.setClientNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri); authSession.setClientNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE); authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName())); return authSession; } public boolean isAuthenticationSessionFresh() { return authenticationSessionFresh; } public AuthenticationSessionModel getAuthenticationSession() { return authenticationSession; } public void setAuthenticationSession(AuthenticationSessionModel authenticationSession, boolean isFresh) { this.authenticationSession = authenticationSession; this.authenticationSessionFresh = isFresh; if (this.event != null) { ClientModel client = authenticationSession == null ? null : authenticationSession.getClient(); this.event.client((String) (client == null ? null : client.getClientId())); } } public ActionTokenHandler<T> getHandler() { return handler; } public String getExecutionId() { return executionId; } public void setExecutionId(String executionId) { this.executionId = executionId; } public Response processFlow(boolean action, String flowPath, AuthenticationFlowModel flow, String errorMessage, AuthenticationProcessor processor) { return processAuthenticateFlow.processFlow(action, getExecutionId(), getAuthenticationSession(), flowPath, flow, errorMessage, processor); } public Response brokerFlow(String code, String flowPath) { return processBrokerFlow.brokerLoginFlow(code, getExecutionId(), flowPath); } }