impersonation
This commit is contained in:
parent
6c9708c700
commit
6e55604dc3
22 changed files with 625 additions and 190 deletions
45
forms/common-themes/src/main/resources/theme/base/login/impersonate.ftl
Executable file
45
forms/common-themes/src/main/resources/theme/base/login/impersonate.ftl
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
<#import "template.ftl" as layout>
|
||||||
|
<@layout.registrationLayout displayInfo=social.displayInfo; section>
|
||||||
|
<#if section = "title">
|
||||||
|
${msg("imperonateTitle",(realm.name!''))}
|
||||||
|
<#elseif section = "header">
|
||||||
|
${msg("impersonateTitleHtml",(realm.name!''))}
|
||||||
|
<#elseif section = "form">
|
||||||
|
<form id="kc-form-login" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||||
|
<input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
|
||||||
|
<#if realmList??>
|
||||||
|
<div class="${properties.kcFormGroupClass!}">
|
||||||
|
<div class="${properties.kcLabelWrapperClass!}">
|
||||||
|
<label for="realm" class="${properties.kcLabelClass!}">${msg("realmChoice")}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="${properties.kcInputWrapperClass!}">
|
||||||
|
<select class="${properties.kcInputClass!}" id="selectRealm" name="realm">
|
||||||
|
<#list realmList as r>
|
||||||
|
<option value="${r}">${r}</option>
|
||||||
|
</#list>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
<div class="${properties.kcFormGroupClass!}">
|
||||||
|
<div class="${properties.kcLabelWrapperClass!}">
|
||||||
|
<label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="${properties.kcInputWrapperClass!}">
|
||||||
|
<input id="username" class="${properties.kcInputClass!}" name="username" value="" type="text" autofocus />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="${properties.kcFormGroupClass!}">
|
||||||
|
<div class="${properties.kcLabelWrapperClass!}">
|
||||||
|
<label for="username" class="${properties.kcLabelClass!}"></label>
|
||||||
|
</div>
|
||||||
|
<div class="${properties.kcInputWrapperClass!}">
|
||||||
|
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="impersonate" id="kc-impersonate" type="submit" value="${msg("doImpersonate")}"/>
|
||||||
|
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doCancel")}"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</#if>
|
||||||
|
</@layout.registrationLayout>
|
|
@ -9,6 +9,7 @@ doDecline=Decline
|
||||||
doContinue=Continue
|
doContinue=Continue
|
||||||
doForgotPassword=Passwort vergessen?
|
doForgotPassword=Passwort vergessen?
|
||||||
doClickHere=hier klicken
|
doClickHere=hier klicken
|
||||||
|
doImpersonate=Impersonate
|
||||||
kerberosNotConfigured=Kerberos Not Configured
|
kerberosNotConfigured=Kerberos Not Configured
|
||||||
kerberosNotConfiguredTitle=Kerberos Not Configured
|
kerberosNotConfiguredTitle=Kerberos Not Configured
|
||||||
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||||
|
@ -24,6 +25,10 @@ loginOauthTitle=
|
||||||
loginOauthTitleHtml=Tempor\u00E4rer zugriff auf <strong>{0}</strong> angefordert von <strong>{1}</strong>.
|
loginOauthTitleHtml=Tempor\u00E4rer zugriff auf <strong>{0}</strong> angefordert von <strong>{1}</strong>.
|
||||||
loginTotpTitle=Mobile Authentifizierung Einrichten
|
loginTotpTitle=Mobile Authentifizierung Einrichten
|
||||||
loginProfileTitle=Benutzerkonto Informationen aktualisieren
|
loginProfileTitle=Benutzerkonto Informationen aktualisieren
|
||||||
|
impersonateTitle={0} Impersonate User
|
||||||
|
impersonateTitleHtml=<strong>{0}</strong> Impersonate User</strong>
|
||||||
|
unknownUser=Unknown user
|
||||||
|
realmChoice=Realm
|
||||||
oauthGrantTitle=OAuth gew\u00E4hren
|
oauthGrantTitle=OAuth gew\u00E4hren
|
||||||
oauthGrantTitleHtml=Tempor\u00E4rer zugriff auf <strong>{0}</strong> angefordert von
|
oauthGrantTitleHtml=Tempor\u00E4rer zugriff auf <strong>{0}</strong> angefordert von
|
||||||
errorTitle=Es tut uns leid...
|
errorTitle=Es tut uns leid...
|
||||||
|
|
|
@ -9,6 +9,7 @@ doAccept=Accept
|
||||||
doDecline=Decline
|
doDecline=Decline
|
||||||
doForgotPassword=Forgot Password?
|
doForgotPassword=Forgot Password?
|
||||||
doClickHere=Click here
|
doClickHere=Click here
|
||||||
|
doImpersonate=Impersonate
|
||||||
kerberosNotConfigured=Kerberos Not Configured
|
kerberosNotConfigured=Kerberos Not Configured
|
||||||
kerberosNotConfiguredTitle=Kerberos Not Configured
|
kerberosNotConfiguredTitle=Kerberos Not Configured
|
||||||
bypassKerberosDetail=Either you are not logged in via Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means
|
bypassKerberosDetail=Either you are not logged in via Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||||
|
@ -17,6 +18,10 @@ registerWithTitle=Register with {0}
|
||||||
registerWithTitleHtml=Register with <strong>{0}</strong>
|
registerWithTitleHtml=Register with <strong>{0}</strong>
|
||||||
loginTitle=Log in to {0}
|
loginTitle=Log in to {0}
|
||||||
loginTitleHtml=Log in to <strong>{0}</strong>
|
loginTitleHtml=Log in to <strong>{0}</strong>
|
||||||
|
impersonateTitle={0} Impersonate User
|
||||||
|
impersonateTitleHtml=<strong>{0}</strong> Impersonate User</strong>
|
||||||
|
realmChoice=Realm
|
||||||
|
unknownUser=Unknown user
|
||||||
loginTotpTitle=Mobile Authenticator Setup
|
loginTotpTitle=Mobile Authenticator Setup
|
||||||
loginProfileTitle=Update Account Information
|
loginProfileTitle=Update Account Information
|
||||||
oauthGrantTitle=OAuth Grant
|
oauthGrantTitle=OAuth Grant
|
||||||
|
@ -76,7 +81,6 @@ emailInstruction=Enter your username or email address and we will send you instr
|
||||||
copyCodeInstruction=Please copy this code and paste it into your application:
|
copyCodeInstruction=Please copy this code and paste it into your application:
|
||||||
|
|
||||||
personalInfo=Personal Info:
|
personalInfo=Personal Info:
|
||||||
|
|
||||||
role_admin=Admin
|
role_admin=Admin
|
||||||
role_realm-admin=Realm Admin
|
role_realm-admin=Realm Admin
|
||||||
role_create-realm=Create realm
|
role_create-realm=Create realm
|
||||||
|
|
|
@ -9,6 +9,7 @@ doDecline=Decline
|
||||||
doContinue=Continue
|
doContinue=Continue
|
||||||
doForgotPassword=Password Dimenticata?
|
doForgotPassword=Password Dimenticata?
|
||||||
doClickHere=Clicca qui
|
doClickHere=Clicca qui
|
||||||
|
doImpersonate=Impersonate
|
||||||
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||||
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
||||||
kerberosNotConfigured=Kerberos Not Configured
|
kerberosNotConfigured=Kerberos Not Configured
|
||||||
|
@ -22,6 +23,10 @@ loginTitle=Accedi a {0}
|
||||||
loginTitleHtml=Accedi a <strong>{0}</strong>
|
loginTitleHtml=Accedi a <strong>{0}</strong>
|
||||||
loginTotpTitle=Configura Autenticazione Mobile
|
loginTotpTitle=Configura Autenticazione Mobile
|
||||||
loginProfileTitle=Aggiorna Profilo
|
loginProfileTitle=Aggiorna Profilo
|
||||||
|
impersonateTitle={0} Impersonate User
|
||||||
|
impersonateTitleHtml=<strong>{0}</strong> Impersonate User</strong>
|
||||||
|
unknownUser=Unknown user
|
||||||
|
realmChoice=Realm
|
||||||
oauthGrantTitle=OAuth Grant
|
oauthGrantTitle=OAuth Grant
|
||||||
oauthGrantTitleHtml=Accesso temporaneo per <strong>{0}</strong> richiesto da
|
oauthGrantTitleHtml=Accesso temporaneo per <strong>{0}</strong> richiesto da
|
||||||
errorTitle=Siamo spiacenti...
|
errorTitle=Siamo spiacenti...
|
||||||
|
|
|
@ -9,6 +9,7 @@ doNo=N\u00E3o
|
||||||
doContinue=Continue
|
doContinue=Continue
|
||||||
doForgotPassword=Esqueceu sua senha?
|
doForgotPassword=Esqueceu sua senha?
|
||||||
doClickHere=Clique aqui
|
doClickHere=Clique aqui
|
||||||
|
doImpersonate=Impersonate
|
||||||
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
bypassKerberos=Your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||||
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
||||||
kerberosNotConfigured=Kerberos Not Configured
|
kerberosNotConfigured=Kerberos Not Configured
|
||||||
|
@ -20,6 +21,10 @@ registerWithTitle=Registre-se com {0}
|
||||||
registerWithTitleHtml=Registre-se com <strong>{0}</strong>
|
registerWithTitleHtml=Registre-se com <strong>{0}</strong>
|
||||||
loginTitle=Entrar em {0}
|
loginTitle=Entrar em {0}
|
||||||
loginTitleHtml=Entrar em <strong>{0}</strong>
|
loginTitleHtml=Entrar em <strong>{0}</strong>
|
||||||
|
impersonateTitle={0} Impersonate User
|
||||||
|
impersonateTitleHtml=<strong>{0}</strong> Impersonate User</strong>
|
||||||
|
unknownUser=Unknown user
|
||||||
|
realmChoice=Realm
|
||||||
loginTotpTitle=Configura\u00E7\u00E3o do autenticador mobile
|
loginTotpTitle=Configura\u00E7\u00E3o do autenticador mobile
|
||||||
loginProfileTitle=Atualiza\u00E7\u00E3o das Informa\u00E7\u00F5es da Conta
|
loginProfileTitle=Atualiza\u00E7\u00E3o das Informa\u00E7\u00F5es da Conta
|
||||||
oauthGrantTitle=Concess\u00E3o OAuth
|
oauthGrantTitle=Concess\u00E3o OAuth
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.migration.migrators;
|
package org.keycloak.migration.migrators;
|
||||||
|
|
||||||
import org.keycloak.migration.ModelVersion;
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
import org.keycloak.models.ImpersonationServiceConstants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||||
|
@ -15,7 +16,6 @@ import java.util.List;
|
||||||
public class MigrateTo1_4_0 {
|
public class MigrateTo1_4_0 {
|
||||||
public static final ModelVersion VERSION = new ModelVersion("1.4.0");
|
public static final ModelVersion VERSION = new ModelVersion("1.4.0");
|
||||||
|
|
||||||
|
|
||||||
public void migrate(KeycloakSession session) {
|
public void migrate(KeycloakSession session) {
|
||||||
List<RealmModel> realms = session.realms().getRealms();
|
List<RealmModel> realms = session.realms().getRealms();
|
||||||
for (RealmModel realm : realms) {
|
for (RealmModel realm : realms) {
|
||||||
|
@ -23,6 +23,7 @@ public class MigrateTo1_4_0 {
|
||||||
DefaultAuthenticationFlows.addFlows(realm);
|
DefaultAuthenticationFlows.addFlows(realm);
|
||||||
DefaultRequiredActions.addActions(realm);
|
DefaultRequiredActions.addActions(realm);
|
||||||
}
|
}
|
||||||
|
ImpersonationServiceConstants.setupImpersonationService(session, realm, session.getContext().getContextPath());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ public interface Constants {
|
||||||
String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
|
String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
|
||||||
|
|
||||||
String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
|
String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
|
||||||
|
String IMPERSONATION_SERVICE_CLIENT_ID = "impersonation";
|
||||||
String BROKER_SERVICE_CLIENT_ID = "broker";
|
String BROKER_SERVICE_CLIENT_ID = "broker";
|
||||||
String REALM_MANAGEMENT_CLIENT_ID = "realm-management";
|
String REALM_MANAGEMENT_CLIENT_ID = "realm-management";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class ImpersonationServiceConstants {
|
||||||
|
public static String IMPERSONATION_ALLOWED = "impersonation";
|
||||||
|
|
||||||
|
public static void setupMasterRealmRole(RealmProvider model, RealmModel realm) {
|
||||||
|
RealmModel adminRealm;
|
||||||
|
RoleModel adminRole;
|
||||||
|
|
||||||
|
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||||
|
adminRealm = realm;
|
||||||
|
adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||||
|
} else {
|
||||||
|
adminRealm = model.getRealmByName(Config.getAdminRealm());
|
||||||
|
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
|
||||||
|
}
|
||||||
|
ClientModel realmAdminApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm));
|
||||||
|
RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ALLOWED);
|
||||||
|
impersonationRole.setDescription("${role_" + IMPERSONATION_ALLOWED + "}");
|
||||||
|
adminRole.addCompositeRole(impersonationRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setupRealmRole(RealmModel realm) {
|
||||||
|
if (realm.getName().equals(Config.getAdminRealm())) { return; } // don't need to do this for master realm
|
||||||
|
String realmAdminApplicationClientId = Constants.REALM_MANAGEMENT_CLIENT_ID;
|
||||||
|
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
|
||||||
|
RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ALLOWED);
|
||||||
|
impersonationRole.setDescription("${role_" + IMPERSONATION_ALLOWED + "}");
|
||||||
|
RoleModel adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
|
||||||
|
adminRole.addCompositeRole(impersonationRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void setupImpersonationService(KeycloakSession session, RealmModel realm, String contextPath) {
|
||||||
|
ClientModel client = realm.getClientNameMap().get(Constants.IMPERSONATION_SERVICE_CLIENT_ID);
|
||||||
|
if (client == null) {
|
||||||
|
client = KeycloakModelUtils.createClient(realm, Constants.IMPERSONATION_SERVICE_CLIENT_ID);
|
||||||
|
client.setName("${client_" + Constants.IMPERSONATION_SERVICE_CLIENT_ID + "}");
|
||||||
|
client.setEnabled(true);
|
||||||
|
client.setFullScopeAllowed(false);
|
||||||
|
String base = contextPath + "/realms/" + realm.getName() + "/impersonate";
|
||||||
|
String redirectUri = base + "/*";
|
||||||
|
client.addRedirectUri(redirectUri);
|
||||||
|
client.setBaseUrl(base);
|
||||||
|
|
||||||
|
setupMasterRealmRole(session.realms(), realm);
|
||||||
|
setupRealmRole(realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ import javax.ws.rs.core.UriInfo;
|
||||||
*/
|
*/
|
||||||
public interface KeycloakContext {
|
public interface KeycloakContext {
|
||||||
|
|
||||||
|
String getContextPath();
|
||||||
|
|
||||||
UriInfo getUri();
|
UriInfo getUri();
|
||||||
|
|
||||||
HttpHeaders getRequestHeaders();
|
HttpHeaders getRequestHeaders();
|
||||||
|
|
|
@ -131,7 +131,7 @@ public class SamlService {
|
||||||
return ErrorPage.error(session, Messages.INVALID_REQUEST);
|
return ErrorPage.error(session, Messages.INVALID_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
|
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false);
|
||||||
if (authResult == null) {
|
if (authResult == null) {
|
||||||
logger.warn("Unknown saml response.");
|
logger.warn("Unknown saml response.");
|
||||||
event.event(EventType.LOGOUT);
|
event.event(EventType.LOGOUT);
|
||||||
|
@ -354,7 +354,7 @@ public class SamlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
|
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
|
||||||
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
|
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false);
|
||||||
if (authResult != null) {
|
if (authResult != null) {
|
||||||
String logoutBinding = getBindingType();
|
String logoutBinding = getBindingType();
|
||||||
if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING)))
|
if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING)))
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class CookieAuthenticator implements Authenticator {
|
||||||
@Override
|
@Override
|
||||||
public void authenticate(AuthenticatorContext context) {
|
public void authenticate(AuthenticatorContext context) {
|
||||||
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(context.getSession(),
|
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(context.getSession(),
|
||||||
context.getRealm(), context.getUriInfo(), context.getConnection(), context.getHttpRequest().getHttpHeaders(), true);
|
context.getRealm(), true);
|
||||||
if (authResult == null) {
|
if (authResult == null) {
|
||||||
context.attempted();
|
context.attempted();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -117,7 +117,7 @@ public class LogoutEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
|
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
|
||||||
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
|
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, false);
|
||||||
if (authResult != null) {
|
if (authResult != null) {
|
||||||
userSession = userSession != null ? userSession : authResult.getSession();
|
userSession = userSession != null ? userSession : authResult.getSession();
|
||||||
if (redirect != null) userSession.setNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI, redirect);
|
if (redirect != null) userSession.setNote(OIDCLoginProtocol.LOGOUT_REDIRECT_URI, redirect);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.keycloak.ClientConnection;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakContext;
|
import org.keycloak.models.KeycloakContext;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -20,6 +21,12 @@ public class DefaultKeycloakContext implements KeycloakContext {
|
||||||
|
|
||||||
private ClientConnection connection;
|
private ClientConnection connection;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContextPath() {
|
||||||
|
KeycloakApplication app = ResteasyProviderFactory.getContextData(KeycloakApplication.class);
|
||||||
|
return app.getContextPath();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UriInfo getUri() {
|
public UriInfo getUri() {
|
||||||
return ResteasyProviderFactory.getContextData(UriInfo.class);
|
return ResteasyProviderFactory.getContextData(UriInfo.class);
|
||||||
|
|
|
@ -172,7 +172,7 @@ public class Urls {
|
||||||
return realmBase(baseUri).path("{realm}").build(realmId).toString();
|
return realmBase(baseUri).path("{realm}").build(realmId).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UriBuilder realmBase(URI baseUri) {
|
public static UriBuilder realmBase(URI baseUri) {
|
||||||
return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
|
return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,12 @@ public class AppAuthManager extends AuthenticationManager {
|
||||||
protected static Logger logger = Logger.getLogger(AppAuthManager.class);
|
protected static Logger logger = Logger.getLogger(AppAuthManager.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
|
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm) {
|
||||||
AuthResult authResult = super.authenticateIdentityCookie(session, realm, uriInfo, connection, headers);
|
AuthResult authResult = super.authenticateIdentityCookie(session, realm);
|
||||||
if (authResult == null) return null;
|
if (authResult == null) return null;
|
||||||
// refresh the cookies!
|
// refresh the cookies!
|
||||||
createLoginCookie(realm, authResult.getUser(), authResult.getSession(), uriInfo, connection);
|
createLoginCookie(realm, authResult.getUser(), authResult.getSession(), session.getContext().getUri(), session.getContext().getConnection());
|
||||||
if (authResult.getSession().isRememberMe()) createRememberMeCookie(realm, authResult.getUser().getUsername(), uriInfo, connection);
|
if (authResult.getSession().isRememberMe()) createRememberMeCookie(realm, authResult.getUser().getUsername(), session.getContext().getUri(), session.getContext().getConnection());
|
||||||
return authResult;
|
return authResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -359,21 +359,21 @@ public class AuthenticationManager {
|
||||||
CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly);
|
CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
|
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm) {
|
||||||
return authenticateIdentityCookie(session, realm, uriInfo, connection, headers, true);
|
return authenticateIdentityCookie(session, realm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers, boolean checkActive) {
|
public static AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, boolean checkActive) {
|
||||||
Cookie cookie = headers.getCookies().get(KEYCLOAK_IDENTITY_COOKIE);
|
Cookie cookie = session.getContext().getRequestHeaders().getCookies().get(KEYCLOAK_IDENTITY_COOKIE);
|
||||||
if (cookie == null || "".equals(cookie.getValue())) {
|
if (cookie == null || "".equals(cookie.getValue())) {
|
||||||
logger.debugv("Could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE);
|
logger.debugv("Could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String tokenString = cookie.getValue();
|
String tokenString = cookie.getValue();
|
||||||
AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, checkActive, tokenString, headers);
|
AuthResult authResult = verifyIdentityToken(session, realm, session.getContext().getUri(), session.getContext().getConnection(), checkActive, tokenString, session.getContext().getRequestHeaders());
|
||||||
if (authResult == null) {
|
if (authResult == null) {
|
||||||
expireIdentityCookie(realm, uriInfo, connection);
|
expireIdentityCookie(realm, session.getContext().getUri(), session.getContext().getConnection());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
authResult.getSession().setLastSessionRefresh(Time.currentTime());
|
authResult.getSession().setLastSessionRefresh(Time.currentTime());
|
||||||
|
@ -399,9 +399,9 @@ public class AuthenticationManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
|
|
||||||
// refresh the cookies!
|
// refresh the cookies!
|
||||||
createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
|
createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
|
||||||
|
if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
|
||||||
if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
|
if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
|
||||||
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
|
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
|
||||||
protocol.setRealm(realm)
|
protocol.setRealm(realm)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.BrowserSecurityHeaders;
|
import org.keycloak.models.BrowserSecurityHeaders;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.ImpersonationServiceConstants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RealmProvider;
|
import org.keycloak.models.RealmProvider;
|
||||||
|
@ -88,6 +89,7 @@ public class RealmManager {
|
||||||
setupAccountManagement(realm);
|
setupAccountManagement(realm);
|
||||||
setupBrokerService(realm);
|
setupBrokerService(realm);
|
||||||
setupAdminConsole(realm);
|
setupAdminConsole(realm);
|
||||||
|
setupImpersonationService(realm);
|
||||||
setupAuthenticationFlows(realm);
|
setupAuthenticationFlows(realm);
|
||||||
setupRequiredActions(realm);
|
setupRequiredActions(realm);
|
||||||
|
|
||||||
|
@ -233,6 +235,10 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setupImpersonationService(RealmModel realm) {
|
||||||
|
ImpersonationServiceConstants.setupImpersonationService(session, realm, contextPath);
|
||||||
|
}
|
||||||
|
|
||||||
public void setupBrokerService(RealmModel realm) {
|
public void setupBrokerService(RealmModel realm) {
|
||||||
ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
|
ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
|
@ -261,6 +267,8 @@ public class RealmManager {
|
||||||
setupMasterAdminManagement(realm);
|
setupMasterAdminManagement(realm);
|
||||||
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
|
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
|
||||||
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
|
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
|
||||||
|
if (!hasImpersonationServiceClient(rep)) setupImpersonationService(realm);
|
||||||
|
|
||||||
if (!hasBrokerClient(rep)) setupBrokerService(realm);
|
if (!hasBrokerClient(rep)) setupBrokerService(realm);
|
||||||
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
|
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
|
||||||
|
|
||||||
|
@ -297,6 +305,15 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
private boolean hasImpersonationServiceClient(RealmRepresentation rep) {
|
||||||
|
if (rep.getClients() == null) return false;
|
||||||
|
for (ClientRepresentation clientRep : rep.getClients()) {
|
||||||
|
if (clientRep.getClientId().equals(Constants.IMPERSONATION_SERVICE_CLIENT_ID)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
private boolean hasBrokerClient(RealmRepresentation rep) {
|
private boolean hasBrokerClient(RealmRepresentation rep) {
|
||||||
if (rep.getClients() == null) return false;
|
if (rep.getClients() == null) return false;
|
||||||
for (ClientRepresentation clientRep : rep.getClients()) {
|
for (ClientRepresentation clientRep : rep.getClients()) {
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
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.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||||
|
import org.keycloak.services.ForbiddenException;
|
||||||
|
import org.keycloak.services.Urls;
|
||||||
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
|
import org.keycloak.services.managers.Auth;
|
||||||
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
import org.keycloak.services.util.CookieHelper;
|
||||||
|
import org.keycloak.util.UriUtils;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.Cookie;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
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;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for securing local services. Provides login basics as well as CSRF check basics
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSecuredLocalService {
|
||||||
|
private static final Logger logger = Logger.getLogger(AbstractSecuredLocalService.class);
|
||||||
|
protected final ClientModel client;
|
||||||
|
protected RealmModel realm;
|
||||||
|
|
||||||
|
@Context
|
||||||
|
protected UriInfo uriInfo;
|
||||||
|
@Context
|
||||||
|
protected HttpHeaders headers;
|
||||||
|
@Context
|
||||||
|
protected ClientConnection clientConnection;
|
||||||
|
protected String stateChecker;
|
||||||
|
@Context
|
||||||
|
protected KeycloakSession session;
|
||||||
|
@Context
|
||||||
|
protected HttpRequest request;
|
||||||
|
protected Auth auth;
|
||||||
|
|
||||||
|
public AbstractSecuredLocalService(RealmModel realm, ClientModel client) {
|
||||||
|
this.realm = realm;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("login-redirect")
|
||||||
|
@GET
|
||||||
|
public Response loginRedirect(@QueryParam("code") String code,
|
||||||
|
@QueryParam("state") String state,
|
||||||
|
@QueryParam("error") String error,
|
||||||
|
@QueryParam("path") String path,
|
||||||
|
@QueryParam("referrer") String referrer,
|
||||||
|
@Context HttpHeaders headers) {
|
||||||
|
try {
|
||||||
|
if (error != null) {
|
||||||
|
logger.debug("error from oauth");
|
||||||
|
throw new ForbiddenException("error");
|
||||||
|
}
|
||||||
|
if (path != null && !getValidPaths().contains(path)) {
|
||||||
|
throw new BadRequestException("Invalid path");
|
||||||
|
}
|
||||||
|
if (!realm.isEnabled()) {
|
||||||
|
logger.debug("realm not enabled");
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
if (!client.isEnabled()) {
|
||||||
|
logger.debug("account management app not enabled");
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
if (code == null) {
|
||||||
|
logger.debug("code not specified");
|
||||||
|
throw new BadRequestException("code not specified");
|
||||||
|
}
|
||||||
|
if (state == null) {
|
||||||
|
logger.debug("state not specified");
|
||||||
|
throw new BadRequestException("state not specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uri = getBaseRedirectUri();
|
||||||
|
URI redirectUri = path != null ? uri.resolve(path) : uri;
|
||||||
|
if (referrer != null) {
|
||||||
|
redirectUri = redirectUri.resolve("?referrer=" + referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.status(302).location(redirectUri).build();
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateCsrfChecks() {
|
||||||
|
Cookie cookie = headers.getCookies().get(AccountService.KEYCLOAK_STATE_CHECKER);
|
||||||
|
if (cookie != null) {
|
||||||
|
stateChecker = cookie.getValue();
|
||||||
|
} else {
|
||||||
|
stateChecker = UUID.randomUUID().toString();
|
||||||
|
String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo);
|
||||||
|
boolean secureOnly = realm.getSslRequired().isRequired(clientConnection);
|
||||||
|
CookieHelper.addCookie(AccountService.KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, -1, secureOnly, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Set<String> getValidPaths();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if form post has sessionId hidden field and match it against the session id.
|
||||||
|
*
|
||||||
|
* @param formData
|
||||||
|
*/
|
||||||
|
protected void csrfCheck(final MultivaluedMap<String, String> formData) {
|
||||||
|
if (!auth.isCookieAuthenticated()) return;
|
||||||
|
String stateChecker = formData.getFirst("stateChecker");
|
||||||
|
if (!this.stateChecker.equals(stateChecker)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if form post has sessionId hidden field and match it against the session id.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected void csrfCheck(String stateChecker) {
|
||||||
|
if (!auth.isCookieAuthenticated()) return;
|
||||||
|
if (auth.getSession() == null) return;
|
||||||
|
if (!this.stateChecker.equals(stateChecker)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract URI getBaseRedirectUri();
|
||||||
|
|
||||||
|
protected Response login(String path) {
|
||||||
|
OAuthRedirect oauth = new OAuthRedirect();
|
||||||
|
String authUrl = OIDCLoginProtocolService.authUrl(uriInfo).build(realm.getName()).toString();
|
||||||
|
oauth.setAuthUrl(authUrl);
|
||||||
|
|
||||||
|
oauth.setClientId(client.getClientId());
|
||||||
|
|
||||||
|
UriBuilder uriBuilder = UriBuilder.fromUri(getBaseRedirectUri()).path("login-redirect");
|
||||||
|
|
||||||
|
if (path != null) {
|
||||||
|
uriBuilder.queryParam("path", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
String referrer = uriInfo.getQueryParameters().getFirst("referrer");
|
||||||
|
if (referrer != null) {
|
||||||
|
uriBuilder.queryParam("referrer", referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
String referrerUri = uriInfo.getQueryParameters().getFirst("referrer_uri");
|
||||||
|
if (referrerUri != null) {
|
||||||
|
uriBuilder.queryParam("referrer_uri", referrerUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
URI accountUri = uriBuilder.build(realm.getName());
|
||||||
|
|
||||||
|
oauth.setStateCookiePath(accountUri.getRawPath());
|
||||||
|
return oauth.redirect(uriInfo, accountUri.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response authenticateBrowser() {
|
||||||
|
AppAuthManager authManager = new AppAuthManager();
|
||||||
|
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm);
|
||||||
|
if (authResult != null) {
|
||||||
|
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), true);
|
||||||
|
} else {
|
||||||
|
return login(null);
|
||||||
|
}
|
||||||
|
// don't allow cors requests
|
||||||
|
// This is to prevent CSRF attacks.
|
||||||
|
String requestOrigin = UriUtils.getOrigin(uriInfo.getBaseUri());
|
||||||
|
String origin = headers.getRequestHeaders().getFirst("Origin");
|
||||||
|
if (origin != null && !requestOrigin.equals(origin)) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.getHttpMethod().equals("GET")) {
|
||||||
|
String referrer = headers.getRequestHeaders().getFirst("Referer");
|
||||||
|
if (referrer != null && !requestOrigin.equals(UriUtils.getOrigin(referrer))) {
|
||||||
|
throw new ForbiddenException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateCsrfChecks();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -98,7 +98,7 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class AccountService {
|
public class AccountService extends AbstractSecuredLocalService {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AccountService.class);
|
private static final Logger logger = Logger.getLogger(AccountService.class);
|
||||||
|
|
||||||
|
@ -128,34 +128,13 @@ public class AccountService {
|
||||||
|
|
||||||
public static final String KEYCLOAK_STATE_CHECKER = "KEYCLOAK_STATE_CHECKER";
|
public static final String KEYCLOAK_STATE_CHECKER = "KEYCLOAK_STATE_CHECKER";
|
||||||
|
|
||||||
private RealmModel realm;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private HttpRequest request;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
protected HttpHeaders headers;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private UriInfo uriInfo;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private ClientConnection clientConnection;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private KeycloakSession session;
|
|
||||||
|
|
||||||
private final AppAuthManager authManager;
|
private final AppAuthManager authManager;
|
||||||
private final ClientModel client;
|
|
||||||
private EventBuilder event;
|
private EventBuilder event;
|
||||||
private AccountProvider account;
|
private AccountProvider account;
|
||||||
private Auth auth;
|
|
||||||
private EventStoreProvider eventStore;
|
private EventStoreProvider eventStore;
|
||||||
private String stateChecker;
|
|
||||||
|
|
||||||
public AccountService(RealmModel realm, ClientModel client, EventBuilder event) {
|
public AccountService(RealmModel realm, ClientModel client, EventBuilder event) {
|
||||||
this.realm = realm;
|
super(realm, client);
|
||||||
this.client = client;
|
|
||||||
this.event = event;
|
this.event = event;
|
||||||
this.authManager = new AppAuthManager();
|
this.authManager = new AppAuthManager();
|
||||||
}
|
}
|
||||||
|
@ -169,18 +148,10 @@ public class AccountService {
|
||||||
if (authResult != null) {
|
if (authResult != null) {
|
||||||
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), false);
|
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), false);
|
||||||
} else {
|
} else {
|
||||||
authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers);
|
authResult = authManager.authenticateIdentityCookie(session, realm);
|
||||||
if (authResult != null) {
|
if (authResult != null) {
|
||||||
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), true);
|
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), client, authResult.getSession(), true);
|
||||||
Cookie cookie = headers.getCookies().get(KEYCLOAK_STATE_CHECKER);
|
updateCsrfChecks();
|
||||||
if (cookie != null) {
|
|
||||||
stateChecker = cookie.getValue();
|
|
||||||
} else {
|
|
||||||
stateChecker = UUID.randomUUID().toString();
|
|
||||||
String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo);
|
|
||||||
boolean secureOnly = realm.getSslRequired().isRequired(clientConnection);
|
|
||||||
CookieHelper.addCookie(KEYCLOAK_STATE_CHECKER, stateChecker, cookiePath, null, null, -1, secureOnly, true);
|
|
||||||
}
|
|
||||||
account.setStateChecker(stateChecker);
|
account.setStateChecker(stateChecker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,10 +207,18 @@ public class AccountService {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UriBuilder accountServiceApplicationPage(UriInfo uriInfo) {
|
||||||
|
return accountServiceBaseUrl(uriInfo).path(AccountService.class, "applicationsPage");
|
||||||
|
}
|
||||||
|
|
||||||
public static UriBuilder accountServiceBaseUrl(UriBuilder base) {
|
public static UriBuilder accountServiceBaseUrl(UriBuilder base) {
|
||||||
return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService");
|
return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Set<String> getValidPaths() {
|
||||||
|
return AccountService.VALID_PATHS;
|
||||||
|
}
|
||||||
|
|
||||||
private Response forwardToPage(String path, AccountPages page) {
|
private Response forwardToPage(String path, AccountPages page) {
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -367,33 +346,6 @@ public class AccountService {
|
||||||
return forwardToPage("applications", AccountPages.APPLICATIONS);
|
return forwardToPage("applications", AccountPages.APPLICATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if form post has sessionId hidden field and match it against the session id.
|
|
||||||
*
|
|
||||||
* @param formData
|
|
||||||
*/
|
|
||||||
protected void csrfCheck(final MultivaluedMap<String, String> formData) {
|
|
||||||
if (!auth.isCookieAuthenticated()) return;
|
|
||||||
String stateChecker = formData.getFirst("stateChecker");
|
|
||||||
if (!this.stateChecker.equals(stateChecker)) {
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check to see if form post has sessionId hidden field and match it against the session id.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected void csrfCheck(String stateChecker) {
|
|
||||||
if (!auth.isCookieAuthenticated()) return;
|
|
||||||
if (auth.getSession() == null) return;
|
|
||||||
if (!this.stateChecker.equals(stateChecker)) {
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update account information.
|
* Update account information.
|
||||||
*
|
*
|
||||||
|
@ -799,77 +751,9 @@ public class AccountService {
|
||||||
return RealmsResource.accountUrl(base).path(AccountService.class, "loginRedirect");
|
return RealmsResource.accountUrl(base).path(AccountService.class, "loginRedirect");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("login-redirect")
|
@Override
|
||||||
@GET
|
protected URI getBaseRedirectUri() {
|
||||||
public Response loginRedirect(@QueryParam("code") String code,
|
return Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName());
|
||||||
@QueryParam("state") String state,
|
|
||||||
@QueryParam("error") String error,
|
|
||||||
@QueryParam("path") String path,
|
|
||||||
@QueryParam("referrer") String referrer,
|
|
||||||
@Context HttpHeaders headers) {
|
|
||||||
try {
|
|
||||||
if (error != null) {
|
|
||||||
logger.debug("error from oauth");
|
|
||||||
throw new ForbiddenException("error");
|
|
||||||
}
|
|
||||||
if (path != null && !VALID_PATHS.contains(path)) {
|
|
||||||
throw new BadRequestException("Invalid path");
|
|
||||||
}
|
|
||||||
if (!realm.isEnabled()) {
|
|
||||||
logger.debug("realm not enabled");
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
if (!client.isEnabled()) {
|
|
||||||
logger.debug("account management app not enabled");
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
if (code == null) {
|
|
||||||
logger.debug("code not specified");
|
|
||||||
throw new BadRequestException("code not specified");
|
|
||||||
}
|
|
||||||
if (state == null) {
|
|
||||||
logger.debug("state not specified");
|
|
||||||
throw new BadRequestException("state not specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
URI accountUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName());
|
|
||||||
URI redirectUri = path != null ? accountUri.resolve(path) : accountUri;
|
|
||||||
if (referrer != null) {
|
|
||||||
redirectUri = redirectUri.resolve("?referrer=" + referrer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.status(302).location(redirectUri).build();
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Response login(String path) {
|
|
||||||
OAuthRedirect oauth = new OAuthRedirect();
|
|
||||||
String authUrl = OIDCLoginProtocolService.authUrl(uriInfo).build(realm.getName()).toString();
|
|
||||||
oauth.setAuthUrl(authUrl);
|
|
||||||
|
|
||||||
oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
|
|
||||||
|
|
||||||
UriBuilder uriBuilder = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect");
|
|
||||||
|
|
||||||
if (path != null) {
|
|
||||||
uriBuilder.queryParam("path", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
String referrer = uriInfo.getQueryParameters().getFirst("referrer");
|
|
||||||
if (referrer != null) {
|
|
||||||
uriBuilder.queryParam("referrer", referrer);
|
|
||||||
}
|
|
||||||
|
|
||||||
String referrerUri = uriInfo.getQueryParameters().getFirst("referrer_uri");
|
|
||||||
if (referrerUri != null) {
|
|
||||||
uriBuilder.queryParam("referrer_uri", referrerUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
URI accountUri = uriBuilder.build(realm.getName());
|
|
||||||
|
|
||||||
oauth.setStateCookiePath(accountUri.getRawPath());
|
|
||||||
return oauth.redirect(uriInfo, accountUri.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPasswordSet(UserModel user) {
|
public static boolean isPasswordSet(UserModel user) {
|
||||||
|
@ -954,43 +838,4 @@ 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
177
services/src/main/java/org/keycloak/services/resources/ImpersonationService.java
Executable file
177
services/src/main/java/org/keycloak/services/resources/ImpersonationService.java
Executable file
|
@ -0,0 +1,177 @@
|
||||||
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.events.EventBuilder;
|
||||||
|
import org.keycloak.login.LoginFormsProvider;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.ImpersonationServiceConstants;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.services.ErrorPage;
|
||||||
|
import org.keycloak.services.ForbiddenException;
|
||||||
|
import org.keycloak.services.Urls;
|
||||||
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
import org.keycloak.services.messages.Messages;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class ImpersonationService extends AbstractSecuredLocalService {
|
||||||
|
|
||||||
|
public static final String UNKNOWN_USER_MESSAGE = "unknownUser";
|
||||||
|
private EventBuilder event;
|
||||||
|
|
||||||
|
public ImpersonationService(RealmModel realm, ClientModel client, EventBuilder event) {
|
||||||
|
super(realm, client);
|
||||||
|
this.event = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> VALID_PATHS = new HashSet<String>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> getValidPaths() {
|
||||||
|
return VALID_PATHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URI getBaseRedirectUri() {
|
||||||
|
return Urls.realmBase(uriInfo.getBaseUri()).path(RealmsResource.class, "getImpersonationService").build(realm.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
public Response impersonatePage() {
|
||||||
|
Response challenge = authenticateBrowser();
|
||||||
|
if (challenge != null) return challenge;
|
||||||
|
LoginFormsProvider page = page();
|
||||||
|
return renderPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LoginFormsProvider page() {
|
||||||
|
UserModel user = auth.getUser();
|
||||||
|
LoginFormsProvider page = session.getProvider(LoginFormsProvider.class)
|
||||||
|
.setActionUri(getBaseRedirectUri())
|
||||||
|
.setAttribute("stateChecker", stateChecker);
|
||||||
|
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||||
|
List<String> realms = new LinkedList<>();
|
||||||
|
for (RealmModel possibleRealm : session.realms().getRealms()) {
|
||||||
|
ClientModel realmAdminApp = realm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(possibleRealm));
|
||||||
|
RoleModel role = realmAdminApp.getRole(ImpersonationServiceConstants.IMPERSONATION_ALLOWED);
|
||||||
|
if (user.hasRole(role)) {
|
||||||
|
realms.add(possibleRealm.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (realms.isEmpty()) {
|
||||||
|
throw new ForbiddenException("not authorized to access impersonation", ErrorPage.error(session, Messages.NO_ACCESS));
|
||||||
|
}
|
||||||
|
if (realms.size() > 1 || !realms.get(0).equals(realm.getName())) {
|
||||||
|
page.setAttribute("realmList", realms);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authorizeCurrentRealm();
|
||||||
|
} return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response renderPage(LoginFormsProvider page) {
|
||||||
|
return page
|
||||||
|
.createForm("impersonate.ftl", new HashMap<String, Object>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void authorizeMaster(String realmName) {
|
||||||
|
RealmModel possibleRealm = session.realms().getRealmByName(realmName);
|
||||||
|
if (possibleRealm == null) {
|
||||||
|
throw new NotFoundException("Could not find realm");
|
||||||
|
}
|
||||||
|
ClientModel realmAdminApp = realm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(possibleRealm));
|
||||||
|
RoleModel role = realmAdminApp.getRole(ImpersonationServiceConstants.IMPERSONATION_ALLOWED);
|
||||||
|
if (!auth.getUser().hasRole(role)) {
|
||||||
|
throw new ForbiddenException("not authorized to access impersonation", ErrorPage.error(session, Messages.NO_ACCESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void authorizeCurrentRealm() {
|
||||||
|
UserModel user = auth.getUser();
|
||||||
|
String realmAdminApplicationClientId = Constants.REALM_MANAGEMENT_CLIENT_ID;
|
||||||
|
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
|
||||||
|
RoleModel role = realmAdminApp.getRole(ImpersonationServiceConstants.IMPERSONATION_ALLOWED);
|
||||||
|
if (!user.hasRole(role)) {
|
||||||
|
throw new ForbiddenException("not authorized to access impersonation", ErrorPage.error(session, Messages.NO_ACCESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
public Response impersonate() {
|
||||||
|
Response challenge = authenticateBrowser();
|
||||||
|
if (challenge != null) return challenge;
|
||||||
|
MultivaluedMap<String, String> formData = request.getDecodedFormParameters();
|
||||||
|
String realmName = formData.getFirst("realm");
|
||||||
|
RealmModel chosenRealm = null;
|
||||||
|
if (realmName == null) {
|
||||||
|
chosenRealm = realm;
|
||||||
|
} else{
|
||||||
|
chosenRealm = session.realms().getRealmByName(realmName);
|
||||||
|
if (chosenRealm == null) {
|
||||||
|
throw new NotFoundException("Could not find realm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||||
|
authorizeMaster(chosenRealm.getName());
|
||||||
|
} else {
|
||||||
|
if (realmName == null) authorizeCurrentRealm();
|
||||||
|
else {
|
||||||
|
throw new ForbiddenException("not authorized to access impersonation", ErrorPage.error(session, Messages.NO_ACCESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csrfCheck(formData);
|
||||||
|
|
||||||
|
if (formData.containsKey("cancel")) {
|
||||||
|
return renderPage(page());
|
||||||
|
}
|
||||||
|
String username = formData.getFirst(AuthenticationManager.FORM_USERNAME);
|
||||||
|
if (username == null) {
|
||||||
|
return renderPage(
|
||||||
|
page().setError(UNKNOWN_USER_MESSAGE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
UserModel user = session.users().getUserByUsername(username, chosenRealm);
|
||||||
|
if (user == null) {
|
||||||
|
user = session.users().getUserByEmail(username, chosenRealm);
|
||||||
|
}
|
||||||
|
if (user == null) {
|
||||||
|
return renderPage(
|
||||||
|
page().setError(UNKNOWN_USER_MESSAGE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// if same realm logout before impersonation
|
||||||
|
if (chosenRealm.getId().equals(realm.getId())) {
|
||||||
|
AuthenticationManager.backchannelLogout(session, realm, auth.getSession(), uriInfo, clientConnection, headers, true);
|
||||||
|
}
|
||||||
|
UserSessionModel userSession = session.sessions().createUserSession(chosenRealm, user, username, clientConnection.getRemoteAddr(), "impersonate", false, null, null);
|
||||||
|
AuthenticationManager.createLoginCookie(chosenRealm, userSession.getUser(), userSession, uriInfo, clientConnection);
|
||||||
|
URI redirect = AccountService.accountServiceApplicationPage(uriInfo).build(chosenRealm.getName());
|
||||||
|
return Response.status(302).location(redirect).build();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,13 +61,14 @@ public class KeycloakApplication extends Application {
|
||||||
public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
|
public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
|
this.contextPath = context.getContextPath();
|
||||||
this.sessionFactory = createSessionFactory();
|
this.sessionFactory = createSessionFactory();
|
||||||
|
|
||||||
dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
|
dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
|
||||||
this.contextPath = context.getContextPath();
|
|
||||||
BruteForceProtector protector = new BruteForceProtector(sessionFactory);
|
BruteForceProtector protector = new BruteForceProtector(sessionFactory);
|
||||||
dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
|
dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
|
||||||
ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
|
ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
|
||||||
|
ResteasyProviderFactory.pushContext(KeycloakApplication.class, this); // for injection
|
||||||
protector.start();
|
protector.start();
|
||||||
context.setAttribute(BruteForceProtector.class.getName(), protector);
|
context.setAttribute(BruteForceProtector.class.getName(), protector);
|
||||||
context.setAttribute(KeycloakSessionFactory.class.getName(), this.sessionFactory);
|
context.setAttribute(KeycloakSessionFactory.class.getName(), this.sessionFactory);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.ClientConnection;
|
||||||
import org.keycloak.authentication.RequiredActionProvider;
|
|
||||||
import org.keycloak.events.EventBuilder;
|
import org.keycloak.events.EventBuilder;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
|
@ -149,6 +148,22 @@ public class RealmsResource {
|
||||||
return accountService;
|
return accountService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("{realm}/impersonate")
|
||||||
|
public ImpersonationService getImpersonationService(final @PathParam("realm") String name) {
|
||||||
|
RealmModel realm = init(name);
|
||||||
|
|
||||||
|
ClientModel client = realm.getClientNameMap().get(Constants.IMPERSONATION_SERVICE_CLIENT_ID);
|
||||||
|
if (client == null || !client.isEnabled()) {
|
||||||
|
logger.debug("impersonate service not enabled");
|
||||||
|
throw new NotFoundException("impersonate service not enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
||||||
|
ImpersonationService impersonateService = new ImpersonationService(realm, client, event);
|
||||||
|
ResteasyProviderFactory.getInstance().injectProperties(impersonateService);
|
||||||
|
return impersonateService;
|
||||||
|
}
|
||||||
|
|
||||||
@Path("{realm}")
|
@Path("{realm}")
|
||||||
public PublicRealmResource getRealmResource(final @PathParam("realm") String name) {
|
public PublicRealmResource getRealmResource(final @PathParam("realm") String name) {
|
||||||
RealmModel realm = init(name);
|
RealmModel realm = init(name);
|
||||||
|
|
Loading…
Reference in a new issue