keycloak-memoizeit

Merge pull request #3239 from stianst/SERVER-PROFILE KEYCLOAK-3579

9/20/2016 5:39:05 AM

Changes

pom.xml 1(+1 -0)

Details

diff --git a/common/src/main/java/org/keycloak/common/Profile.java b/common/src/main/java/org/keycloak/common/Profile.java
new file mode 100755
index 0000000..ac16874
--- /dev/null
+++ b/common/src/main/java/org/keycloak/common/Profile.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.common;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Profile {
+
+    private enum ProfileValue {
+        PRODUCT, PREVIEW, COMMUNITY
+    }
+
+    private static ProfileValue value = load();
+
+    static ProfileValue load() {
+        String profile = null;
+        try {
+            profile = System.getProperty("keycloak.profile");
+            if (profile == null) {
+                String jbossServerConfigDir = System.getProperty("jboss.server.config.dir");
+                if (jbossServerConfigDir != null) {
+                    File file = new File(jbossServerConfigDir, "profile.properties");
+                    if (file.isFile()) {
+                        Properties props = new Properties();
+                        props.load(new FileInputStream(file));
+                        profile = props.getProperty("profile");
+                    }
+                }
+            }
+        } catch (Exception e) {
+        }
+
+        if (profile == null) {
+            return ProfileValue.valueOf(Version.DEFAULT_PROFILE.toUpperCase());
+        } else {
+            return ProfileValue.valueOf(profile.toUpperCase());
+        }
+    }
+
+    public static String getName() {
+        return value.name().toLowerCase();
+    }
+
+    public static boolean isPreviewEnabled() {
+        return value.ordinal() >= ProfileValue.PREVIEW.ordinal();
+    }
+
+}
diff --git a/common/src/main/java/org/keycloak/common/Version.java b/common/src/main/java/org/keycloak/common/Version.java
index 42ba52a..862ccd2 100755
--- a/common/src/main/java/org/keycloak/common/Version.java
+++ b/common/src/main/java/org/keycloak/common/Version.java
@@ -32,6 +32,7 @@ public class Version {
     public static String VERSION;
     public static String RESOURCES_VERSION;
     public static String BUILD_TIME;
+    public static String DEFAULT_PROFILE;
 
     static {
         Properties props = new Properties();
@@ -40,6 +41,7 @@ public class Version {
             props.load(is);
             Version.NAME = props.getProperty("name");
             Version.NAME_HTML = props.getProperty("name-html");
+            Version.DEFAULT_PROFILE = props.getProperty("default-profile");
             Version.VERSION = props.getProperty("version");
             Version.BUILD_TIME = props.getProperty("build-time");
             Version.RESOURCES_VERSION = Version.VERSION.toLowerCase();
diff --git a/common/src/main/resources/keycloak-version.properties b/common/src/main/resources/keycloak-version.properties
index 643b6de..f66e436 100755
--- a/common/src/main/resources/keycloak-version.properties
+++ b/common/src/main/resources/keycloak-version.properties
@@ -18,4 +18,5 @@
 name=${product.name}
 name-html=${product.name-html}
 version=${product.version}
-build-time=${product.build-time}
\ No newline at end of file
+build-time=${product.build-time}
+default-profile=${product.default-profile}
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/info/ProfileInfoRepresentation.java b/core/src/main/java/org/keycloak/representations/info/ProfileInfoRepresentation.java
new file mode 100644
index 0000000..3c474d0
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/info/ProfileInfoRepresentation.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.info;
+
+import org.keycloak.common.Profile;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ProfileInfoRepresentation {
+
+    private String name;
+    private boolean previewEnabled;
+
+    public static ProfileInfoRepresentation create() {
+        ProfileInfoRepresentation info = new ProfileInfoRepresentation();
+        info.setName(Profile.getName());
+        info.setPreviewEnabled(Profile.isPreviewEnabled());
+        return info;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isPreviewEnabled() {
+        return previewEnabled;
+    }
+
+    public void setPreviewEnabled(boolean previewEnabled) {
+        this.previewEnabled = previewEnabled;
+    }
+
+}
diff --git a/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java b/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
index 59d400e..8c98ce3 100755
--- a/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
@@ -32,6 +32,7 @@ public class ServerInfoRepresentation {
 
     private SystemInfoRepresentation systemInfo;
     private MemoryInfoRepresentation memoryInfo;
+    private ProfileInfoRepresentation profileInfo;
 
     private Map<String, List<ThemeInfoRepresentation>> themes;
 
@@ -66,6 +67,14 @@ public class ServerInfoRepresentation {
         this.memoryInfo = memoryInfo;
     }
 
+    public ProfileInfoRepresentation getProfileInfo() {
+        return profileInfo;
+    }
+
+    public void setProfileInfo(ProfileInfoRepresentation profileInfo) {
+        this.profileInfo = profileInfo;
+    }
+
     public Map<String, List<ThemeInfoRepresentation>> getThemes() {
         return themes;
     }

pom.xml 1(+1 -0)

diff --git a/pom.xml b/pom.xml
index e1a47ce..da7a2ea 100755
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,7 @@
         <product.name-html>\u003Cdiv class="kc-logo-text"\u003E\u003Cspan\u003EKeycloak\u003C\u002Fspan\u003E\u003C\u002Fdiv\u003E</product.name-html>
         <product.version>${project.version}</product.version>
         <product.build-time>${timestamp}</product.build-time>
+        <product.default-profile>community</product.default-profile>
 
         <!-- WildFly -->
         <eap.version>7.0.0.Beta</eap.version>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index d208b50..955dff0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -18,9 +18,9 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.BadRequestException;
-import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.authorization.admin.AuthorizationService;
+import org.keycloak.common.Profile;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
@@ -52,10 +52,12 @@ import org.keycloak.common.util.Time;
 import org.keycloak.services.validation.ClientValidator;
 import org.keycloak.services.validation.PairwiseClientValidator;
 import org.keycloak.services.validation.ValidationMessages;
+import org.keycloak.utils.ProfileHelper;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
@@ -153,10 +155,12 @@ public class ClientResource {
 
         RepresentationToModel.updateClient(rep, client);
 
-        if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
-            authorization().enable();
-        } else {
-            authorization().disable();
+        if (Profile.isPreviewEnabled()) {
+            if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
+                authorization().enable();
+            } else {
+                authorization().disable();
+            }
         }
     }
 
@@ -177,7 +181,9 @@ public class ClientResource {
 
         ClientRepresentation representation = ModelToRepresentation.toRepresentation(client);
 
-        representation.setAuthorizationServicesEnabled(authorization().isEnabled());
+        if (Profile.isPreviewEnabled()) {
+            representation.setAuthorizationServicesEnabled(authorization().isEnabled());
+        }
 
         return representation;
     }
@@ -562,6 +568,8 @@ public class ClientResource {
 
     @Path("/authz")
     public AuthorizationService authorization() {
+        ProfileHelper.requirePreview();
+
         AuthorizationService resource = new AuthorizationService(this.session, this.client, this.auth);
 
         ResteasyProviderFactory.getInstance().injectProperties(resource);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
index a7195e1..638e657 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
@@ -43,6 +43,7 @@ import org.keycloak.policy.PasswordPolicyProviderFactory;
 import org.keycloak.provider.*;
 import org.keycloak.representations.idm.ComponentTypeRepresentation;
 import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation;
+import org.keycloak.representations.info.ProfileInfoRepresentation;
 import org.keycloak.theme.Theme;
 import org.keycloak.theme.ThemeProvider;
 import org.keycloak.models.KeycloakSession;
@@ -84,6 +85,7 @@ public class ServerInfoAdminResource {
         ServerInfoRepresentation info = new ServerInfoRepresentation();
         info.setSystemInfo(SystemInfoRepresentation.create(session.getKeycloakSessionFactory().getServerStartupTimestamp()));
         info.setMemoryInfo(MemoryInfoRepresentation.create());
+        info.setProfileInfo(ProfileInfoRepresentation.create());
 
         setSocialProviders(info);
         setIdentityProviders(info);
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 1e42e7b..d0ca449 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -35,6 +35,7 @@ import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resource.RealmResourceProvider;
 import org.keycloak.services.util.CacheControlUtil;
 import org.keycloak.services.util.ResolveRelative;
+import org.keycloak.utils.ProfileHelper;
 import org.keycloak.wellknown.WellKnownProvider;
 
 import javax.ws.rs.GET;
@@ -254,6 +255,8 @@ public class RealmsResource {
 
     @Path("{realm}/authz")
     public Object getAuthorizationService(@PathParam("realm") String name) {
+        ProfileHelper.requirePreview();
+
         init(name);
         AuthorizationProvider authorization = this.session.getProvider(AuthorizationProvider.class);
         AuthorizationService service = new AuthorizationService(authorization);
diff --git a/services/src/main/java/org/keycloak/utils/ProfileHelper.java b/services/src/main/java/org/keycloak/utils/ProfileHelper.java
new file mode 100644
index 0000000..719bd24
--- /dev/null
+++ b/services/src/main/java/org/keycloak/utils/ProfileHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.utils;
+
+import org.keycloak.common.Profile;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ProfileHelper {
+
+    public static void requirePreview() {
+        if (!Profile.isPreviewEnabled()) {
+            throw new WebApplicationException("Feature not available in current profile", Response.Status.NOT_IMPLEMENTED);
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/ProfileAssume.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/ProfileAssume.java
new file mode 100644
index 0000000..7fbf59b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/ProfileAssume.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite;
+
+import org.junit.Assume;
+import org.keycloak.common.Profile;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ProfileAssume {
+
+    public static void assumePreview() {
+        Assume.assumeTrue("Ignoring test as community/preview profile is not enabled", Profile.isPreviewEnabled());
+    }
+
+    public static void assumePreviewDisabled() {
+        Assume.assumeFalse("Ignoring test as community/preview profile is enabled", Profile.isPreviewEnabled());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
index c4979e0..2c3aac7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
@@ -19,11 +19,13 @@ package org.keycloak.testsuite.admin.client.authorization;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ResourceScopeResource;
 import org.keycloak.admin.client.resource.ResourceScopesResource;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.testsuite.ProfileAssume;
 import org.keycloak.testsuite.admin.client.AbstractClientTest;
 
 import javax.ws.rs.core.Response;
@@ -38,6 +40,11 @@ public abstract class AbstractAuthorizationTest extends AbstractClientTest {
 
     protected static final String RESOURCE_SERVER_CLIENT_ID = "test-resource-server";
 
+    @BeforeClass
+    public static void enabled() {
+        ProfileAssume.assumePreview();
+    }
+
     @Before
     public void onBeforeAuthzTests() {
         createOidcClient(RESOURCE_SERVER_CLIENT_ID);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationDisabledInPreviewTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationDisabledInPreviewTest.java
new file mode 100644
index 0000000..072aa5f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationDisabledInPreviewTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.testsuite.ProfileAssume;
+import org.keycloak.testsuite.admin.client.AbstractClientTest;
+
+import javax.ws.rs.ServerErrorException;
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuthorizationDisabledInPreviewTest extends AbstractClientTest {
+
+    @BeforeClass
+    public static void enabled() {
+        ProfileAssume.assumePreviewDisabled();
+    }
+
+    @Test
+    public void testAuthzServicesRemoved() {
+        String id = testRealmResource().clients().findAll().get(0).getId();
+        try {
+            testRealmResource().clients().get(id).authorization().getSettings();
+        } catch (ServerErrorException e) {
+            assertEquals(Response.Status.NOT_IMPLEMENTED.getStatusCode(), e.getResponse().getStatus());
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientAuthorizationServicesAvailableTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientAuthorizationServicesAvailableTest.java
new file mode 100644
index 0000000..0dcf08b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/ClientAuthorizationServicesAvailableTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.console.clients;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Test;
+import org.keycloak.common.Profile;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.testsuite.ProfileAssume;
+import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
+import org.openqa.selenium.By;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.auth.page.login.Login.OIDC;
+
+/**
+ *
+ * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
+ */
+public class ClientAuthorizationServicesAvailableTest extends AbstractClientTest {
+
+    private ClientRepresentation newClient;
+
+    @Page
+    private ClientSettings clientSettingsPage;
+
+    @Test
+    public void authzServicesAvailable() {
+        ProfileAssume.assumePreview();
+
+        newClient = createClientRep("oidc-public", OIDC);
+        createClient(newClient);
+        assertEquals("oidc-public", clientSettingsPage.form().getClientId());
+
+        assertTrue(driver.findElement(By.xpath("//*[@for='authorizationServicesEnabled']")).isDisplayed());
+    }
+
+    @Test
+    public void authzServicesUnavailable() throws InterruptedException {
+        ProfileAssume.assumePreviewDisabled();
+
+        newClient = createClientRep("oidc-public", OIDC);
+        createClient(newClient);
+        assertEquals("oidc-public", clientSettingsPage.form().getClientId());
+
+        assertFalse(driver.findElement(By.xpath("//*[@for='authorizationServicesEnabled']")).isDisplayed());
+
+    }
+}
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index ea34268..d3cdd9e 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -851,6 +851,7 @@ include-representation=Include Representation
 include-representation.tooltip=Include JSON representation for create and update requests.
 clear-admin-events.tooltip=Deletes all admin events in the database.
 server-version=Server Version
+server-profile=Server Profile
 info=Info
 providers=Providers
 server-time=Server Time
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index 6d8fdcd..a063143 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -274,7 +274,7 @@ module.service('ServerInfo', function($resource, $q, $http) {
     var delay = $q.defer();
 
     $http.get(authUrl + '/admin/serverinfo').success(function(data) {
-        info = data;
+        angular.copy(data, info);
         delay.resolve(info);
     });
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index d8f0d24..9fb3a2d 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -110,7 +110,7 @@
                     <input ng-model="client.serviceAccountsEnabled" name="serviceAccountsEnabled" id="serviceAccountsEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
                 </div>
             </div>
-            <div class="form-group" data-ng-show="protocol == 'openid-connect'">
+            <div class="form-group" data-ng-show="serverInfo.profileInfo.previewEnabled && protocol == 'openid-connect'">
                 <label class="col-md-2 control-label" for="authorizationServicesEnabled">{{:: 'authz-authorization-services-enabled' | translate}}</label>
                 <kc-tooltip>{{:: 'authz-authorization-services-enabled.tooltip' | translate}}</kc-tooltip>
                 <div class="col-md-6">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/server-info.html b/themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
index 0607250..299a93b 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/server-info.html
@@ -15,6 +15,10 @@
             <td>{{serverInfo.systemInfo.version}}</td>
         </tr>
         <tr>
+            <td width="20%">{{:: 'server-profile' | translate}}</td>
+            <td>{{serverInfo.profileInfo.name}}</td>
+        </tr>
+        <tr>
             <td>{{:: 'server-time' | translate}}</td>
             <td>{{serverInfo.systemInfo.serverTime}}</td>
         </tr>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
index f39bc2c..e2d5db2 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
@@ -19,7 +19,7 @@
             <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/scope-mappings">{{:: 'scope' | translate}}</a>
             <kc-tooltip>{{:: 'scope.tooltip' | translate}}</kc-tooltip>
         </li>
-        <li ng-class="{active: path[4] == 'authz'}" data-ng-show="!disableAuthorizationTab && client.authorizationServicesEnabled"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li ng-class="{active: path[4] == 'authz'}" data-ng-show="serverInfo.profileInfo.previewEnabled && !disableAuthorizationTab && client.authorizationServicesEnabled"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/revocation">{{:: 'revocation' | translate}}</a></li>
     <!--    <li ng-class="{active: path[4] == 'identity-provider'}" data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/identity-provider">Identity Provider</a></li> -->
         <li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!client.bearerOnly">