per-realm admin

This commit is contained in:
Bill Burke 2014-05-12 10:12:31 -04:00
parent 1194e40ef2
commit 1e1991e285
18 changed files with 217 additions and 77 deletions

View file

@ -57,6 +57,7 @@ public class RealmRepresentation {
protected List<AuthenticationProviderRepresentation> authenticationProviders; protected List<AuthenticationProviderRepresentation> authenticationProviders;
protected String loginTheme; protected String loginTheme;
protected String accountTheme; protected String accountTheme;
protected String adminTheme;
protected boolean auditEnabled; protected boolean auditEnabled;
protected long auditExpiration; protected long auditExpiration;
protected List<String> auditListeners; protected List<String> auditListeners;
@ -377,6 +378,14 @@ public class RealmRepresentation {
this.accountTheme = accountTheme; this.accountTheme = accountTheme;
} }
public String getAdminTheme() {
return adminTheme;
}
public void setAdminTheme(String adminTheme) {
this.adminTheme = adminTheme;
}
public Integer getNotBefore() { public Integer getNotBefore() {
return notBefore; return notBefore;
} }

View file

@ -73,7 +73,7 @@ public class ModelExporter {
this.propertiesManager.setBasicPropertiesFromModel(realmModel, entity); this.propertiesManager.setBasicPropertiesFromModel(realmModel, entity);
// Export 'advanced' properties // Export 'advanced' properties
ApplicationModel realmAdminApp = realmModel.getAdminApp(); ApplicationModel realmAdminApp = realmModel.getMasterAdminApp();
if (realmAdminApp != null) { if (realmAdminApp != null) {
entity.setAdminAppId(realmAdminApp.getId()); entity.setAdminAppId(realmAdminApp.getId());
} }

View file

@ -182,7 +182,7 @@ public class ModelImporter {
// admin app // admin app
String adminAppId = realmEntity.getAdminAppId(); String adminAppId = realmEntity.getAdminAppId();
if (adminAppId != null) { if (adminAppId != null) {
realm.setAdminApp(adminRealm.getApplicationById(adminAppId)); realm.setMasterAdminApp(adminRealm.getApplicationById(adminAppId));
} }
// Default roles // Default roles

View file

@ -99,6 +99,18 @@
</div> </div>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-sm-2 control-label" for="adminTheme">Admin Console Theme</label>
<div class="col-sm-4">
<div class="select-kc">
<select id="adminTheme"
ng-model="realm.adminTheme"
ng-options="o as o for o in serverInfo.themes.admin">
<option value="" disabled selected>Select one...</option>
</select>
</div>
</div>
</div>
</fieldset> </fieldset>
<div class="pull-right form-actions" data-ng-show="createRealm && access.manageRealm"> <div class="pull-right form-actions" data-ng-show="createRealm && access.manageRealm">

View file

@ -9,6 +9,9 @@ public class AdminRoles {
public static String ADMIN = "admin"; public static String ADMIN = "admin";
// for admin application local to each realm
public static String REALM_ADMIN = "realm-admin";
public static String CREATE_REALM = "create-realm"; public static String CREATE_REALM = "create-realm";
public static String VIEW_REALM = "view-realm"; public static String VIEW_REALM = "view-realm";

View file

@ -220,6 +220,10 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
void setAccountTheme(String name); void setAccountTheme(String name);
String getAdminTheme();
void setAdminTheme(String name);
boolean hasScope(ClientModel client, RoleModel role); boolean hasScope(ClientModel client, RoleModel role);
/** /**
@ -245,9 +249,9 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
void setAuditListeners(Set<String> listeners); void setAuditListeners(Set<String> listeners);
ApplicationModel getAdminApp(); ApplicationModel getMasterAdminApp();
void setAdminApp(ApplicationModel app); void setMasterAdminApp(ApplicationModel app);
UserSessionModel createUserSession(UserModel user, String ipAddress); UserSessionModel createUserSession(UserModel user, String ipAddress);

View file

@ -42,6 +42,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private String loginTheme; private String loginTheme;
private String accountTheme; private String accountTheme;
private String adminTheme;
// We are using names of defaultRoles (not ids) // We are using names of defaultRoles (not ids)
private List<String> defaultRoles = new ArrayList<String>(); private List<String> defaultRoles = new ArrayList<String>();
@ -275,6 +276,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
this.accountTheme = accountTheme; this.accountTheme = accountTheme;
} }
public String getAdminTheme() {
return adminTheme;
}
public void setAdminTheme(String adminTheme) {
this.adminTheme = adminTheme;
}
public List<String> getDefaultRoles() { public List<String> getDefaultRoles() {
return defaultRoles; return defaultRoles;
} }

View file

@ -1328,6 +1328,17 @@ public class RealmAdapter implements RealmModel {
em.flush(); em.flush();
} }
@Override
public String getAdminTheme() {
return realm.getAdminTheme();
}
@Override
public void setAdminTheme(String name) {
realm.setAdminTheme(name);
em.flush();
}
@Override @Override
public boolean isAuditEnabled() { public boolean isAuditEnabled() {
return realm.isAuditEnabled(); return realm.isAuditEnabled();
@ -1362,13 +1373,13 @@ public class RealmAdapter implements RealmModel {
} }
@Override @Override
public ApplicationModel getAdminApp() { public ApplicationModel getMasterAdminApp() {
return new ApplicationAdapter(this, em, realm.getAdminApp()); return new ApplicationAdapter(this, em, realm.getMasterAdminApp());
} }
@Override @Override
public void setAdminApp(ApplicationModel app) { public void setMasterAdminApp(ApplicationModel app) {
realm.setAdminApp(((ApplicationAdapter) app).getJpaEntity()); realm.setMasterAdminApp(((ApplicationAdapter) app).getJpaEntity());
em.flush(); em.flush();
} }

View file

@ -74,6 +74,7 @@ public class RealmEntity {
protected String loginTheme; protected String loginTheme;
protected String accountTheme; protected String accountTheme;
protected String adminTheme;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true) @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
@JoinTable(name="User_RequiredCreds") @JoinTable(name="User_RequiredCreds")
@ -109,16 +110,16 @@ public class RealmEntity {
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
@JoinTable(name="RealmDefaultRoles") @JoinTable(name="RealmDefaultRoles")
Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>(); protected Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
private boolean auditEnabled; protected boolean auditEnabled;
private long auditExpiration; protected long auditExpiration;
@ElementCollection @ElementCollection
private Set<String> auditListeners= new HashSet<String>(); protected Set<String> auditListeners= new HashSet<String>();
@OneToOne @OneToOne
private ApplicationEntity adminApp; protected ApplicationEntity masterAdminApp;
public String getId() { public String getId() {
return id; return id;
@ -351,6 +352,14 @@ public class RealmEntity {
this.accountTheme = theme; this.accountTheme = theme;
} }
public String getAdminTheme() {
return adminTheme;
}
public void setAdminTheme(String adminTheme) {
this.adminTheme = adminTheme;
}
public int getNotBefore() { public int getNotBefore() {
return notBefore; return notBefore;
} }
@ -439,12 +448,12 @@ public class RealmEntity {
this.auditListeners = auditListeners; this.auditListeners = auditListeners;
} }
public ApplicationEntity getAdminApp() { public ApplicationEntity getMasterAdminApp() {
return adminApp; return masterAdminApp;
} }
public void setAdminApp(ApplicationEntity adminApp) { public void setMasterAdminApp(ApplicationEntity masterAdminApp) {
this.adminApp = adminApp; this.masterAdminApp = masterAdminApp;
} }
} }

View file

@ -409,6 +409,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
updateRealm(); updateRealm();
} }
@Override
public String getAdminTheme() {
return realm.getAdminTheme();
}
@Override
public void setAdminTheme(String name) {
realm.setAdminTheme(name);
updateRealm();
}
@Override @Override
public UserAdapter getUser(String name) { public UserAdapter getUser(String name) {
DBObject query = new QueryBuilder() DBObject query = new QueryBuilder()
@ -1322,13 +1333,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
} }
@Override @Override
public ApplicationModel getAdminApp() { public ApplicationModel getMasterAdminApp() {
MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext); MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext);
return appData != null ? new ApplicationAdapter(this, appData, invocationContext) : null; return appData != null ? new ApplicationAdapter(this, appData, invocationContext) : null;
} }
@Override @Override
public void setAdminApp(ApplicationModel app) { public void setMasterAdminApp(ApplicationModel app) {
realm.setAdminAppId(app.getId()); realm.setAdminAppId(app.getId());
updateRealm(); updateRealm();
} }

View file

@ -77,7 +77,10 @@ public class ImportTest extends AbstractModelTest {
Assert.assertEquals(0, realm.getSocialLinks(user).size()); Assert.assertEquals(0, realm.getSocialLinks(user).size());
List<ApplicationModel> resources = realm.getApplications(); List<ApplicationModel> resources = realm.getApplications();
Assert.assertEquals(3, resources.size()); for (ApplicationModel app : resources) {
System.out.println("app: " + app.getName());
}
Assert.assertEquals(5, resources.size());
// Test applications imported // Test applications imported
ApplicationModel application = realm.getApplicationByName("Application"); ApplicationModel application = realm.getApplicationByName("Application");
@ -88,7 +91,7 @@ public class ImportTest extends AbstractModelTest {
Assert.assertNotNull(otherApp); Assert.assertNotNull(otherApp);
Assert.assertNull(nonExisting); Assert.assertNull(nonExisting);
Map<String, ApplicationModel> apps = realm.getApplicationNameMap(); Map<String, ApplicationModel> apps = realm.getApplicationNameMap();
Assert.assertEquals(3, apps.size()); Assert.assertEquals(5, apps.size());
Assert.assertTrue(apps.values().contains(application)); Assert.assertTrue(apps.values().contains(application));
Assert.assertTrue(apps.values().contains(otherApp)); Assert.assertTrue(apps.values().contains(otherApp));
Assert.assertTrue(apps.values().contains(accountApp)); Assert.assertTrue(apps.values().contains(accountApp));

View file

@ -49,6 +49,7 @@ public class ApplianceBootstrap {
logger.info("Initializing " + adminRealmName + " realm"); logger.info("Initializing " + adminRealmName + " realm");
RealmManager manager = new RealmManager(session); RealmManager manager = new RealmManager(session);
manager.setContextPath(contextPath);
RealmModel realm = manager.createRealm(adminRealmName, adminRealmName); RealmModel realm = manager.createRealm(adminRealmName, adminRealmName);
realm.setName(adminRealmName); realm.setName(adminRealmName);
realm.setEnabled(true); realm.setEnabled(true);
@ -63,18 +64,8 @@ public class ApplianceBootstrap {
manager.generateRealmKeys(realm); manager.generateRealmKeys(realm);
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER)); realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
ApplicationModel adminConsole = new ApplicationManager(manager).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
adminConsole.setBaseUrl(contextPath + "/admin/index.html");
adminConsole.setEnabled(true);
adminConsole.setPublicClient(true);
adminConsole.addRedirectUri(contextPath + "/admin/" + realm.getName() + "/console/*");
realm.setAuditListeners(Collections.singleton("jboss-logging")); realm.setAuditListeners(Collections.singleton("jboss-logging"));
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
realm.addScopeMapping(adminConsole, adminRole);
UserModel adminUser = realm.addUser("admin"); UserModel adminUser = realm.addUser("admin");
adminUser.setEnabled(true); adminUser.setEnabled(true);
UserCredentialModel password = new UserCredentialModel(); UserCredentialModel password = new UserCredentialModel();
@ -83,6 +74,7 @@ public class ApplianceBootstrap {
realm.updateCredential(adminUser, password); realm.updateCredential(adminUser, password);
adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
realm.grantRole(adminUser, adminRole); realm.grantRole(adminUser, adminRole);
ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP); ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);

View file

@ -99,6 +99,7 @@ public class ModelToRepresentation {
rep.setLdapServer(realm.getLdapServerConfig()); rep.setLdapServer(realm.getLdapServerConfig());
rep.setAccountTheme(realm.getAccountTheme()); rep.setAccountTheme(realm.getAccountTheme());
rep.setLoginTheme(realm.getLoginTheme()); rep.setLoginTheme(realm.getLoginTheme());
rep.setAdminTheme(realm.getAdminTheme());
if (realm.getPasswordPolicy() != null) { if (realm.getPasswordPolicy() != null) {
rep.setPasswordPolicy(realm.getPasswordPolicy().toString()); rep.setPasswordPolicy(realm.getPasswordPolicy().toString());
} }

View file

@ -54,6 +54,15 @@ public class RealmManager {
protected static final Logger logger = Logger.getLogger(RealmManager.class); protected static final Logger logger = Logger.getLogger(RealmManager.class);
protected KeycloakSession identitySession; protected KeycloakSession identitySession;
protected String contextPath = "";
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public RealmManager(KeycloakSession identitySession) { public RealmManager(KeycloakSession identitySession) {
this.identitySession = identitySession; this.identitySession = identitySession;
@ -83,14 +92,39 @@ public class RealmManager {
// setup defaults // setup defaults
setupRealmDefaults(realm); setupRealmDefaults(realm);
setupAdminManagement(realm); setupMasterAdminManagement(realm);
setupRealmAdminManagement(realm);
setupAccountManagement(realm); setupAccountManagement(realm);
setupAdminConsole(realm);
realm.setAuditListeners(Collections.singleton("jboss-logging")); realm.setAuditListeners(Collections.singleton("jboss-logging"));
return realm; return realm;
} }
protected void setupAdminConsole(RealmModel realm) {
ApplicationModel adminConsole = new ApplicationManager(this).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
String baseUrl = contextPath + "/admin/" + realm.getName() + "/console";
adminConsole.setBaseUrl(baseUrl + "/index.html");
adminConsole.setEnabled(true);
adminConsole.setPublicClient(true);
adminConsole.addRedirectUri(baseUrl + "/*");
RoleModel adminRole;
if (realm.getName().equals(Config.getAdminRealm())) {
adminRole = realm.getRole(AdminRoles.ADMIN);
} else {
ApplicationModel realmApp = realm.getApplicationByName(getRealmAdminApplicationName(realm));
adminRole = realmApp.getRole(AdminRoles.REALM_ADMIN);
}
realm.addScopeMapping(adminConsole, adminRole);
}
public String getRealmAdminApplicationName(RealmModel realm) {
return realm.getName() + "-realm";
}
protected void setupRealmDefaults(RealmModel realm) { protected void setupRealmDefaults(RealmModel realm) {
// brute force // brute force
realm.setBruteForceProtected(false); // default settings off for now todo set it on realm.setBruteForceProtected(false); // default settings off for now todo set it on
@ -105,7 +139,7 @@ public class RealmManager {
public boolean removeRealm(RealmModel realm) { public boolean removeRealm(RealmModel realm) {
boolean removed = identitySession.removeRealm(realm.getId()); boolean removed = identitySession.removeRealm(realm.getId());
if (removed) { if (removed) {
getKeycloakAdminstrationRealm().removeApplication(realm.getAdminApp().getId()); getKeycloakAdminstrationRealm().removeApplication(realm.getMasterAdminApp().getId());
} }
return removed; return removed;
} }
@ -153,6 +187,7 @@ public class RealmManager {
} }
if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme()); if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme()); if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy())); if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
@ -189,7 +224,7 @@ public class RealmManager {
} }
} }
private void setupAdminManagement(RealmModel realm) { private void setupMasterAdminManagement(RealmModel realm) {
RealmModel adminRealm; RealmModel adminRealm;
RoleModel adminRole; RoleModel adminRole;
@ -207,9 +242,9 @@ public class RealmManager {
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession)); ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession));
ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, realm.getName() + "-realm"); ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getRealmAdminApplicationName(realm));
realmAdminApp.setBearerOnly(true); realmAdminApp.setBearerOnly(true);
realm.setAdminApp(realmAdminApp); realm.setMasterAdminApp(realmAdminApp);
for (String r : AdminRoles.ALL_REALM_ROLES) { for (String r : AdminRoles.ALL_REALM_ROLES) {
RoleModel role = realmAdminApp.addRole(r); RoleModel role = realmAdminApp.addRole(r);
@ -217,6 +252,22 @@ public class RealmManager {
} }
} }
private void setupRealmAdminManagement(RealmModel realm) {
if (realm.getName().equals(Config.getAdminRealm())) { return; } // don't need to do this for master realm
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession));
ApplicationModel realmAdminApp = applicationManager.createApplication(realm, getRealmAdminApplicationName(realm));
RoleModel adminRole = realmAdminApp.addRole(AdminRoles.REALM_ADMIN);
realmAdminApp.setBearerOnly(true);
for (String r : AdminRoles.ALL_REALM_ROLES) {
RoleModel role = realmAdminApp.addRole(r);
adminRole.addCompositeRole(role);
}
}
private void setupAccountManagement(RealmModel realm) { private void setupAccountManagement(RealmModel realm) {
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP); ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
if (application == null) { if (application == null) {
@ -283,6 +334,7 @@ public class RealmManager {
} }
if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme()); if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme()); if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAccountTheme());
Map<String, UserModel> userMap = new HashMap<String, UserModel>(); Map<String, UserModel> userMap = new HashMap<String, UserModel>();

View file

@ -219,6 +219,7 @@ public class KeycloakApplication extends Application {
try { try {
session.getTransaction().begin(); session.getTransaction().begin();
RealmManager manager = new RealmManager(session); RealmManager manager = new RealmManager(session);
manager.setContextPath(getContextPath());
if (rep.getId() != null && manager.getRealm(rep.getId()) != null) { if (rep.getId() != null && manager.getRealm(rep.getId()) != null) {
log.info("Not importing realm " + rep.getRealm() + " from " + from + ". It already exists."); log.info("Not importing realm " + rep.getRealm() + " from " + from + ". It already exists.");

View file

@ -6,12 +6,8 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse; import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotFoundException; import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.OAuth2Constants;
import org.keycloak.freemarker.Theme; import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeLoader; import org.keycloak.freemarker.ThemeLoader;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Config; import org.keycloak.models.Config;
@ -21,17 +17,12 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken; import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.ApplicationManager; import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.TokenService; import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import javax.activation.FileTypeMap; import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap; import javax.activation.MimetypesFileTypeMap;
@ -39,19 +30,17 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers; import javax.ws.rs.ext.Providers;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -182,7 +171,7 @@ public class AdminConsole {
return Response.status(401).build(); return Response.status(401).build();
} }
String displayName; String displayName;
if (user.getFirstName() != null || user.getLastName() != null) { if ((user.getFirstName() != null && !user.getFirstName().trim().equals("")) || (user.getLastName() != null && !user.getLastName().trim().equals(""))) {
displayName = user.getFirstName(); displayName = user.getFirstName();
if (user.getLastName() != null) { if (user.getLastName() != null) {
displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName(); displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName();
@ -192,41 +181,55 @@ public class AdminConsole {
} }
RealmModel masterRealm = getAdminstrationRealm(realmManager); RealmModel masterRealm = getAdminstrationRealm(realmManager);
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
if (masterRealm == null) if (masterRealm == null)
throw new NotFoundException("No realm found"); throw new NotFoundException("No realm found");
boolean createRealm = false; boolean createRealm = false;
if (realm.equals(masterRealm)) { if (realm.equals(masterRealm)) {
logger.info("setting up realm access for a master realm user");
createRealm = masterRealm.hasRole(user, masterRealm.getRole(AdminRoles.CREATE_REALM)); createRealm = masterRealm.hasRole(user, masterRealm.getRole(AdminRoles.CREATE_REALM));
addMasterRealmAccess(realm, user, realmAccess);
} else {
logger.info("setting up realm access for a realm user");
addRealmAccess(realm, user, realmAccess);
}
if (realmAccess.size() == 0) {
return Response.status(401).build();
} }
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
addRealmAdminAccess(realmAccess, realm.getRoleMappings(user));
return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess)).build(); return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess)).build();
} }
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) { private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
for (RoleModel r : roles) { RealmManager realmManager = new RealmManager(session);
if (r.getContainer() instanceof ApplicationModel) { ApplicationModel realmAdminApp = realm.getApplicationByName(realmManager.getRealmAdminApplicationName(realm));
ApplicationModel app = (ApplicationModel) r.getContainer(); Set<RoleModel> roles = realmAdminApp.getRoles();
if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) { for (RoleModel role : roles) {
String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length()); if (!realm.hasRole(user, role)) continue;
if (!realmAdminAccess.containsKey(realm)) { if (!realmAdminAccess.containsKey(realm.getName())) {
realmAdminAccess.put(realm, new HashSet<String>()); realmAdminAccess.put(realm.getName(), new HashSet<String>());
}
realmAdminAccess.get(realm).add(r.getName());
} }
realmAdminAccess.get(realm.getName()).add(role.getName());
} }
if (r.isComposite()) { }
addRealmAdminAccess(realmAdminAccess, r.getComposites());
private void addMasterRealmAccess(RealmModel masterRealm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
List<RealmModel> realms = session.getRealms();
for (RealmModel realm : realms) {
ApplicationModel realmAdminApp = realm.getMasterAdminApp();
Set<RoleModel> roles = realmAdminApp.getRoles();
for (RoleModel role : roles) {
if (!masterRealm.hasRole(user, role)) continue;
if (!realmAdminAccess.containsKey(realm.getName())) {
realmAdminAccess.put(realm.getName(), new HashSet<String>());
}
realmAdminAccess.get(realm.getName()).add(role.getName());
} }
} }
} }
@Path("logout") @Path("logout")
@GET @GET
@NoCache @NoCache
@ -268,7 +271,12 @@ public class AdminConsole {
@Path("{path:.+}") @Path("{path:.+}")
public Response getResource(@PathParam("path") String path) { public Response getResource(@PathParam("path") String path) {
try { try {
Theme theme = ThemeLoader.createTheme(Config.getThemeAdmin(), Theme.Type.ADMIN); String themeName = realm.getAdminTheme();
if (themeName == null || themeName.trim().equals("")) {
themeName = Config.getThemeAdmin();
}
Theme theme = ThemeLoader.createTheme(themeName, Theme.Type.ADMIN);
InputStream resource = theme.getResourceAsStream(path); InputStream resource = theme.getResourceAsStream(path);
if (resource != null) { if (resource != null) {
String contentType = mimeTypes.getContentType(path); String contentType = mimeTypes.getContentType(path);

View file

@ -145,6 +145,9 @@ public class AdminRoot {
@Path("realms") @Path("realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) { public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
Auth auth = authenticateRealmAdminRequest(headers); Auth auth = authenticateRealmAdminRequest(headers);
if (auth != null) {
logger.info("authenticated admin access for: " + auth.getUser().getLoginName());
}
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager); RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource); ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource); //resourceContext.initResource(adminResource);

View file

@ -19,6 +19,7 @@ import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@ -32,7 +33,6 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -68,6 +68,9 @@ public class RealmsAdminResource {
@Context @Context
protected KeycloakSession session; protected KeycloakSession session;
@Context
protected KeycloakApplication keycloak;
@GET @GET
@NoCache @NoCache
@Produces("application/json") @Produces("application/json")
@ -77,19 +80,20 @@ public class RealmsAdminResource {
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
List<RealmModel> realms = session.getRealms(); List<RealmModel> realms = session.getRealms();
for (RealmModel realm : realms) { for (RealmModel realm : realms) {
addRealmRep(reps, realm); addRealmRep(reps, realm, realm.getMasterAdminApp());
} }
} else { } else {
addRealmRep(reps, auth.getRealm()); ApplicationModel adminApp = auth.getRealm().getApplicationByName(realmManager.getRealmAdminApplicationName(auth.getRealm()));
addRealmRep(reps, auth.getRealm(), adminApp);
} }
logger.debug(("getRealms()")); logger.debug(("getRealms()"));
return reps; return reps;
} }
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) { protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm, ApplicationModel realmManagementApplication) {
if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) { if (auth.hasAppRole(realmManagementApplication, AdminRoles.MANAGE_REALM)) {
reps.add(ModelToRepresentation.toRepresentation(realm)); reps.add(ModelToRepresentation.toRepresentation(realm));
} else if (auth.hasOneOfAppRole(realm.getAdminApp(), AdminRoles.ALL_REALM_ROLES)) { } else if (auth.hasOneOfAppRole(realmManagementApplication, AdminRoles.ALL_REALM_ROLES)) {
RealmRepresentation rep = new RealmRepresentation(); RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName()); rep.setRealm(realm.getName());
reps.add(rep); reps.add(rep);
@ -100,6 +104,7 @@ public class RealmsAdminResource {
@Consumes("application/json") @Consumes("application/json")
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) { public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
realmManager.setContextPath(keycloak.getContextPath());
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -125,6 +130,7 @@ public class RealmsAdminResource {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException { public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
realmManager.setContextPath(keycloak.getContextPath());
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -164,7 +170,7 @@ public class RealmsAdminResource {
} }
RealmModel adminRealm = new RealmManager(session).getKeycloakAdminstrationRealm(); RealmModel adminRealm = new RealmManager(session).getKeycloakAdminstrationRealm();
ApplicationModel realmAdminApp = realm.getAdminApp(); ApplicationModel realmAdminApp = realm.getMasterAdminApp();
for (String r : AdminRoles.ALL_REALM_ROLES) { for (String r : AdminRoles.ALL_REALM_ROLES) {
RoleModel role = realmAdminApp.getRole(r); RoleModel role = realmAdminApp.getRole(r);
adminRealm.grantRole(auth.getUser(), role); adminRealm.grantRole(auth.getUser(), role);
@ -183,7 +189,13 @@ public class RealmsAdminResource {
&& !auth.getRealm().equals(realm)) { && !auth.getRealm().equals(realm)) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
RealmAuth realmAuth = new RealmAuth(auth, realm.getAdminApp()); RealmAuth realmAuth;
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
realmAuth = new RealmAuth(auth, realm.getMasterAdminApp());
} else {
realmAuth = new RealmAuth(auth, realm.getApplicationByName(realmManager.getRealmAdminApplicationName(auth.getRealm())));
}
RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager); RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource); ResteasyProviderFactory.getInstance().injectProperties(adminResource);