diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java index d19495d439..66a0147f73 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -57,6 +57,7 @@ public class RealmRepresentation { protected List authenticationProviders; protected String loginTheme; protected String accountTheme; + protected String adminTheme; protected boolean auditEnabled; protected long auditExpiration; protected List auditListeners; @@ -377,6 +378,14 @@ public class RealmRepresentation { this.accountTheme = accountTheme; } + public String getAdminTheme() { + return adminTheme; + } + + public void setAdminTheme(String adminTheme) { + this.adminTheme = adminTheme; + } + public Integer getNotBefore() { return notBefore; } diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java old mode 100644 new mode 100755 index b1893f390c..cdfdcab44f --- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java +++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java @@ -73,7 +73,7 @@ public class ModelExporter { this.propertiesManager.setBasicPropertiesFromModel(realmModel, entity); // Export 'advanced' properties - ApplicationModel realmAdminApp = realmModel.getAdminApp(); + ApplicationModel realmAdminApp = realmModel.getMasterAdminApp(); if (realmAdminApp != null) { entity.setAdminAppId(realmAdminApp.getId()); } diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java old mode 100644 new mode 100755 index b751d73891..3bfc9aa788 --- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java +++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java @@ -182,7 +182,7 @@ public class ModelImporter { // admin app String adminAppId = realmEntity.getAdminAppId(); if (adminAppId != null) { - realm.setAdminApp(adminRealm.getApplicationById(adminAppId)); + realm.setMasterAdminApp(adminRealm.getApplicationById(adminAppId)); } // Default roles diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-detail.html index 92bd33e43a..d2e60f52be 100755 --- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-detail.html +++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-detail.html @@ -99,6 +99,18 @@ +
+ +
+
+ +
+
+
diff --git a/model/api/src/main/java/org/keycloak/models/AdminRoles.java b/model/api/src/main/java/org/keycloak/models/AdminRoles.java old mode 100644 new mode 100755 index 33e94cdc74..8a31eecd31 --- a/model/api/src/main/java/org/keycloak/models/AdminRoles.java +++ b/model/api/src/main/java/org/keycloak/models/AdminRoles.java @@ -9,6 +9,9 @@ public class AdminRoles { 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 VIEW_REALM = "view-realm"; diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java index fee50d32a7..e3f41eb8ef 100755 --- a/model/api/src/main/java/org/keycloak/models/RealmModel.java +++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java @@ -220,6 +220,10 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa void setAccountTheme(String name); + String getAdminTheme(); + + void setAdminTheme(String name); + boolean hasScope(ClientModel client, RoleModel role); /** @@ -245,9 +249,9 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa void setAuditListeners(Set listeners); - ApplicationModel getAdminApp(); + ApplicationModel getMasterAdminApp(); - void setAdminApp(ApplicationModel app); + void setMasterAdminApp(ApplicationModel app); UserSessionModel createUserSession(UserModel user, String ipAddress); diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java old mode 100644 new mode 100755 index 479d266677..d7fde9cc81 --- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java @@ -42,6 +42,7 @@ public class RealmEntity extends AbstractIdentifiableEntity { private String loginTheme; private String accountTheme; + private String adminTheme; // We are using names of defaultRoles (not ids) private List defaultRoles = new ArrayList(); @@ -275,6 +276,14 @@ public class RealmEntity extends AbstractIdentifiableEntity { this.accountTheme = accountTheme; } + public String getAdminTheme() { + return adminTheme; + } + + public void setAdminTheme(String adminTheme) { + this.adminTheme = adminTheme; + } + public List getDefaultRoles() { return defaultRoles; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index a243d85454..d9c3784a63 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -1328,6 +1328,17 @@ public class RealmAdapter implements RealmModel { em.flush(); } + @Override + public String getAdminTheme() { + return realm.getAdminTheme(); + } + + @Override + public void setAdminTheme(String name) { + realm.setAdminTheme(name); + em.flush(); + } + @Override public boolean isAuditEnabled() { return realm.isAuditEnabled(); @@ -1362,13 +1373,13 @@ public class RealmAdapter implements RealmModel { } @Override - public ApplicationModel getAdminApp() { - return new ApplicationAdapter(this, em, realm.getAdminApp()); + public ApplicationModel getMasterAdminApp() { + return new ApplicationAdapter(this, em, realm.getMasterAdminApp()); } @Override - public void setAdminApp(ApplicationModel app) { - realm.setAdminApp(((ApplicationAdapter) app).getJpaEntity()); + public void setMasterAdminApp(ApplicationModel app) { + realm.setMasterAdminApp(((ApplicationAdapter) app).getJpaEntity()); em.flush(); } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java index ba662f42d1..2051109e48 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -74,6 +74,7 @@ public class RealmEntity { protected String loginTheme; protected String accountTheme; + protected String adminTheme; @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true) @JoinTable(name="User_RequiredCreds") @@ -109,16 +110,16 @@ public class RealmEntity { @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) @JoinTable(name="RealmDefaultRoles") - Collection defaultRoles = new ArrayList(); + protected Collection defaultRoles = new ArrayList(); - private boolean auditEnabled; - private long auditExpiration; + protected boolean auditEnabled; + protected long auditExpiration; @ElementCollection - private Set auditListeners= new HashSet(); + protected Set auditListeners= new HashSet(); @OneToOne - private ApplicationEntity adminApp; + protected ApplicationEntity masterAdminApp; public String getId() { return id; @@ -351,6 +352,14 @@ public class RealmEntity { this.accountTheme = theme; } + public String getAdminTheme() { + return adminTheme; + } + + public void setAdminTheme(String adminTheme) { + this.adminTheme = adminTheme; + } + public int getNotBefore() { return notBefore; } @@ -439,12 +448,12 @@ public class RealmEntity { this.auditListeners = auditListeners; } - public ApplicationEntity getAdminApp() { - return adminApp; + public ApplicationEntity getMasterAdminApp() { + return masterAdminApp; } - public void setAdminApp(ApplicationEntity adminApp) { - this.adminApp = adminApp; + public void setMasterAdminApp(ApplicationEntity masterAdminApp) { + this.masterAdminApp = masterAdminApp; } } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index 82f95c0fd7..cb0e8d7265 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -409,6 +409,17 @@ public class RealmAdapter extends AbstractMongoAdapter impleme updateRealm(); } + @Override + public String getAdminTheme() { + return realm.getAdminTheme(); + } + + @Override + public void setAdminTheme(String name) { + realm.setAdminTheme(name); + updateRealm(); + } + @Override public UserAdapter getUser(String name) { DBObject query = new QueryBuilder() @@ -1322,13 +1333,13 @@ public class RealmAdapter extends AbstractMongoAdapter impleme } @Override - public ApplicationModel getAdminApp() { + public ApplicationModel getMasterAdminApp() { MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext); return appData != null ? new ApplicationAdapter(this, appData, invocationContext) : null; } @Override - public void setAdminApp(ApplicationModel app) { + public void setMasterAdminApp(ApplicationModel app) { realm.setAdminAppId(app.getId()); updateRealm(); } diff --git a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java index 0552a9757b..1c47fd144f 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java @@ -77,7 +77,10 @@ public class ImportTest extends AbstractModelTest { Assert.assertEquals(0, realm.getSocialLinks(user).size()); List 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 ApplicationModel application = realm.getApplicationByName("Application"); @@ -88,7 +91,7 @@ public class ImportTest extends AbstractModelTest { Assert.assertNotNull(otherApp); Assert.assertNull(nonExisting); Map apps = realm.getApplicationNameMap(); - Assert.assertEquals(3, apps.size()); + Assert.assertEquals(5, apps.size()); Assert.assertTrue(apps.values().contains(application)); Assert.assertTrue(apps.values().contains(otherApp)); Assert.assertTrue(apps.values().contains(accountApp)); diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java index 381ca8b329..aff58a7fa6 100755 --- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java +++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java @@ -49,6 +49,7 @@ public class ApplianceBootstrap { logger.info("Initializing " + adminRealmName + " realm"); RealmManager manager = new RealmManager(session); + manager.setContextPath(contextPath); RealmModel realm = manager.createRealm(adminRealmName, adminRealmName); realm.setName(adminRealmName); realm.setEnabled(true); @@ -63,18 +64,8 @@ public class ApplianceBootstrap { manager.generateRealmKeys(realm); 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")); - RoleModel adminRole = realm.getRole(AdminRoles.ADMIN); - - realm.addScopeMapping(adminConsole, adminRole); - UserModel adminUser = realm.addUser("admin"); adminUser.setEnabled(true); UserCredentialModel password = new UserCredentialModel(); @@ -83,6 +74,7 @@ public class ApplianceBootstrap { realm.updateCredential(adminUser, password); adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD); + RoleModel adminRole = realm.getRole(AdminRoles.ADMIN); realm.grantRole(adminUser, adminRole); ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP); diff --git a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java index 5919c265ce..f2d34b8d43 100755 --- a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java +++ b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java @@ -99,6 +99,7 @@ public class ModelToRepresentation { rep.setLdapServer(realm.getLdapServerConfig()); rep.setAccountTheme(realm.getAccountTheme()); rep.setLoginTheme(realm.getLoginTheme()); + rep.setAdminTheme(realm.getAdminTheme()); if (realm.getPasswordPolicy() != null) { rep.setPasswordPolicy(realm.getPasswordPolicy().toString()); } diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index af9cbf459d..2e229bbcf4 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -54,6 +54,15 @@ public class RealmManager { protected static final Logger logger = Logger.getLogger(RealmManager.class); protected KeycloakSession identitySession; + protected String contextPath = ""; + + public String getContextPath() { + return contextPath; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } public RealmManager(KeycloakSession identitySession) { this.identitySession = identitySession; @@ -83,14 +92,39 @@ public class RealmManager { // setup defaults setupRealmDefaults(realm); - setupAdminManagement(realm); + setupMasterAdminManagement(realm); + setupRealmAdminManagement(realm); setupAccountManagement(realm); + setupAdminConsole(realm); realm.setAuditListeners(Collections.singleton("jboss-logging")); 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) { // brute force realm.setBruteForceProtected(false); // default settings off for now todo set it on @@ -105,7 +139,7 @@ public class RealmManager { public boolean removeRealm(RealmModel realm) { boolean removed = identitySession.removeRealm(realm.getId()); if (removed) { - getKeycloakAdminstrationRealm().removeApplication(realm.getAdminApp().getId()); + getKeycloakAdminstrationRealm().removeApplication(realm.getMasterAdminApp().getId()); } return removed; } @@ -153,6 +187,7 @@ public class RealmManager { } if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme()); 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())); @@ -189,7 +224,7 @@ public class RealmManager { } } - private void setupAdminManagement(RealmModel realm) { + private void setupMasterAdminManagement(RealmModel realm) { RealmModel adminRealm; RoleModel adminRole; @@ -207,9 +242,9 @@ public class RealmManager { 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); - realm.setAdminApp(realmAdminApp); + realm.setMasterAdminApp(realmAdminApp); for (String r : AdminRoles.ALL_REALM_ROLES) { 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) { ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP); if (application == null) { @@ -283,6 +334,7 @@ public class RealmManager { } if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme()); if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme()); + if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAccountTheme()); Map userMap = new HashMap(); diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java index c18304ada9..63396a19b4 100755 --- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java +++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java @@ -219,6 +219,7 @@ public class KeycloakApplication extends Application { try { session.getTransaction().begin(); RealmManager manager = new RealmManager(session); + manager.setContextPath(getContextPath()); if (rep.getId() != null && manager.getRealm(rep.getId()) != null) { log.info("Not importing realm " + rep.getRealm() + " from " + from + ". It already exists."); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java index 899e1d0343..a063efa894 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java @@ -6,12 +6,8 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpResponse; 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.ThemeLoader; -import org.keycloak.jose.jws.JWSInput; import org.keycloak.models.AdminRoles; import org.keycloak.models.ApplicationModel; import org.keycloak.models.Config; @@ -21,17 +17,12 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; 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.ApplicationManager; -import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.RealmManager; -import org.keycloak.services.managers.TokenManager; import org.keycloak.services.resources.KeycloakApplication; -import org.keycloak.services.resources.RealmsResource; 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.MimetypesFileTypeMap; @@ -39,19 +30,17 @@ import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Providers; -import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -182,7 +171,7 @@ public class AdminConsole { return Response.status(401).build(); } 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(); if (user.getLastName() != null) { displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName(); @@ -192,41 +181,55 @@ public class AdminConsole { } RealmModel masterRealm = getAdminstrationRealm(realmManager); + Map> realmAccess = new HashMap>(); if (masterRealm == null) throw new NotFoundException("No realm found"); boolean createRealm = false; if (realm.equals(masterRealm)) { + logger.info("setting up realm access for a master realm user"); 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> realmAccess = new HashMap>(); - addRealmAdminAccess(realmAccess, realm.getRoleMappings(user)); return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess)).build(); } - private void addRealmAdminAccess(Map> realmAdminAccess, Set roles) { - for (RoleModel r : roles) { - if (r.getContainer() instanceof ApplicationModel) { - ApplicationModel app = (ApplicationModel) r.getContainer(); - if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) { - String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length()); - if (!realmAdminAccess.containsKey(realm)) { - realmAdminAccess.put(realm, new HashSet()); - } - realmAdminAccess.get(realm).add(r.getName()); - } + private void addRealmAccess(RealmModel realm, UserModel user, Map> realmAdminAccess) { + RealmManager realmManager = new RealmManager(session); + ApplicationModel realmAdminApp = realm.getApplicationByName(realmManager.getRealmAdminApplicationName(realm)); + Set roles = realmAdminApp.getRoles(); + for (RoleModel role : roles) { + if (!realm.hasRole(user, role)) continue; + if (!realmAdminAccess.containsKey(realm.getName())) { + realmAdminAccess.put(realm.getName(), new HashSet()); } + realmAdminAccess.get(realm.getName()).add(role.getName()); + } - if (r.isComposite()) { - addRealmAdminAccess(realmAdminAccess, r.getComposites()); + } + + private void addMasterRealmAccess(RealmModel masterRealm, UserModel user, Map> realmAdminAccess) { + List realms = session.getRealms(); + for (RealmModel realm : realms) { + ApplicationModel realmAdminApp = realm.getMasterAdminApp(); + Set roles = realmAdminApp.getRoles(); + for (RoleModel role : roles) { + if (!masterRealm.hasRole(user, role)) continue; + if (!realmAdminAccess.containsKey(realm.getName())) { + realmAdminAccess.put(realm.getName(), new HashSet()); + } + realmAdminAccess.get(realm.getName()).add(role.getName()); } } } - - - @Path("logout") @GET @NoCache @@ -268,7 +271,12 @@ public class AdminConsole { @Path("{path:.+}") public Response getResource(@PathParam("path") String path) { 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); if (resource != null) { String contentType = mimeTypes.getContentType(path); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java index f3b778a94d..c558d66a9c 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminRoot.java @@ -145,6 +145,9 @@ public class AdminRoot { @Path("realms") public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) { Auth auth = authenticateRealmAdminRequest(headers); + if (auth != null) { + logger.info("authenticated admin access for: " + auth.getUser().getLoginName()); + } RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager); ResteasyProviderFactory.getInstance().injectProperties(adminResource); //resourceContext.initResource(adminResource); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java index b7bb8fb4d8..681eb89891 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java @@ -19,6 +19,7 @@ import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.TokenManager; +import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.flows.Flows; 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.MediaType; import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; @@ -68,6 +68,9 @@ public class RealmsAdminResource { @Context protected KeycloakSession session; + @Context + protected KeycloakApplication keycloak; + @GET @NoCache @Produces("application/json") @@ -77,19 +80,20 @@ public class RealmsAdminResource { if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { List realms = session.getRealms(); for (RealmModel realm : realms) { - addRealmRep(reps, realm); + addRealmRep(reps, realm, realm.getMasterAdminApp()); } } else { - addRealmRep(reps, auth.getRealm()); + ApplicationModel adminApp = auth.getRealm().getApplicationByName(realmManager.getRealmAdminApplicationName(auth.getRealm())); + addRealmRep(reps, auth.getRealm(), adminApp); } logger.debug(("getRealms()")); return reps; } - protected void addRealmRep(List reps, RealmModel realm) { - if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) { + protected void addRealmRep(List reps, RealmModel realm, ApplicationModel realmManagementApplication) { + if (auth.hasAppRole(realmManagementApplication, AdminRoles.MANAGE_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(); rep.setRealm(realm.getName()); reps.add(rep); @@ -100,6 +104,7 @@ public class RealmsAdminResource { @Consumes("application/json") public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) { RealmManager realmManager = new RealmManager(session); + realmManager.setContextPath(keycloak.getContextPath()); if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { throw new ForbiddenException(); } @@ -125,6 +130,7 @@ public class RealmsAdminResource { @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException { RealmManager realmManager = new RealmManager(session); + realmManager.setContextPath(keycloak.getContextPath()); if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) { throw new ForbiddenException(); } @@ -164,7 +170,7 @@ public class RealmsAdminResource { } RealmModel adminRealm = new RealmManager(session).getKeycloakAdminstrationRealm(); - ApplicationModel realmAdminApp = realm.getAdminApp(); + ApplicationModel realmAdminApp = realm.getMasterAdminApp(); for (String r : AdminRoles.ALL_REALM_ROLES) { RoleModel role = realmAdminApp.getRole(r); adminRealm.grantRole(auth.getUser(), role); @@ -183,7 +189,13 @@ public class RealmsAdminResource { && !auth.getRealm().equals(realm)) { 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); ResteasyProviderFactory.getInstance().injectProperties(adminResource);