keycloak-uncached

per-realm admin

5/12/2014 11:12:31 AM

Changes

Details

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 d19495d..66a0147 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<AuthenticationProviderRepresentation> authenticationProviders;
     protected String loginTheme;
     protected String accountTheme;
+    protected String adminTheme;
     protected boolean auditEnabled;
     protected long auditExpiration;
     protected List<String> 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 b1893f3..cdfdcab
--- 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 b751d73..3bfc9aa
--- 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 92bd33e..d2e60f5 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 @@
                             </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>
 
                 <div class="pull-right form-actions" data-ng-show="createRealm && access.manageRealm">
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 33e94cd..8a31eec
--- 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/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
old mode 100644
new mode 100755
index 479d266..d7fde9c
--- 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<String> defaultRoles = new ArrayList<String>();
@@ -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<String> getDefaultRoles() {
         return defaultRoles;
     }
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 fee50d3..e3f41eb 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<String> listeners);
 
-    ApplicationModel getAdminApp();
+    ApplicationModel getMasterAdminApp();
 
-    void setAdminApp(ApplicationModel app);
+    void setMasterAdminApp(ApplicationModel app);
 
     UserSessionModel createUserSession(UserModel user, String ipAddress);
 
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 ba662f4..2051109 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<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
+    protected Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
 
-    private boolean auditEnabled;
-    private long auditExpiration;
+    protected boolean auditEnabled;
+    protected long auditExpiration;
 
     @ElementCollection
-    private Set<String> auditListeners= new HashSet<String>();
+    protected Set<String> auditListeners= new HashSet<String>();
 
     @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/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index a243d85..d9c3784 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
@@ -1329,6 +1329,17 @@ public class RealmAdapter implements RealmModel {
     }
 
     @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/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 82f95c0..cb0e8d7 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
@@ -410,6 +410,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @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()
                 .and("loginName").is(name)
@@ -1322,13 +1333,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> 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 0552a97..1c47fd1 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<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
         ApplicationModel application = realm.getApplicationByName("Application");
@@ -88,7 +91,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertNotNull(otherApp);
         Assert.assertNull(nonExisting);
         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(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 381ca8b..aff58a7 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 5919c26..f2d34b8 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 af9cbf4..2e229bb 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<String, UserModel> userMap = new HashMap<String, UserModel>();
 
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 899e1d0..a063efa 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<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
         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<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();
     }
 
-    private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> 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<String>());
-                    }
-                    realmAdminAccess.get(realm).add(r.getName());
-                }
+    private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
+        RealmManager realmManager = new RealmManager(session);
+        ApplicationModel realmAdminApp = realm.getApplicationByName(realmManager.getRealmAdminApplicationName(realm));
+        Set<RoleModel> roles = realmAdminApp.getRoles();
+        for (RoleModel role : roles) {
+            if (!realm.hasRole(user, role)) continue;
+            if (!realmAdminAccess.containsKey(realm.getName())) {
+                realmAdminAccess.put(realm.getName(), new HashSet<String>());
             }
+            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")
     @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 f3b778a..c558d66 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 b7bb8fb..681eb89 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<RealmModel> 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<RealmRepresentation> reps, RealmModel realm) {
-        if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) {
+    protected void addRealmRep(List<RealmRepresentation> 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);
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 c18304a..63396a1 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.");