Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion js/apps/admin-ui/src/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ import { useRealm } from "./context/realm-context/RealmContext";
import { toDashboard } from "./dashboard/routes/Dashboard";
import { usePreviewLogo } from "./realm-settings/themes/LogoContext";
import { joinPath } from "./utils/joinPath";
import useIsFeatureEnabled, { Feature } from "./utils/useIsFeatureEnabled";
import useToggle from "./utils/useToggle";

const ManageAccountDropdownItem = () => {
const { keycloak } = useEnvironment();

const { t } = useTranslation();
const isFeatureEnabled = useIsFeatureEnabled();

if (!isFeatureEnabled(Feature.AccountV3)) {
return null;
}

return (
<DropdownItem
key="manage account"
Expand Down
1 change: 1 addition & 0 deletions js/apps/admin-ui/src/utils/useIsFeatureEnabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useAccess } from "../context/access/Access";

export enum Feature {
AccountV3 = "ACCOUNT_V3",
AdminFineGrainedAuthz = "ADMIN_FINE_GRAINED_AUTHZ",
AdminFineGrainedAuthzV2 = "ADMIN_FINE_GRAINED_AUTHZ_V2",
ClientPolicies = "CLIENT_POLICIES",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package org.keycloak.services.resource;

import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.ProviderFactory;

/**
* <p>A factory that creates {@link AccountResourceProvider} instances.
*/
public interface AccountResourceProviderFactory extends ProviderFactory<AccountResourceProvider> {
public interface AccountResourceProviderFactory extends ProviderFactory<AccountResourceProvider>, EnvironmentDependentProviderFactory {

@Override
default boolean isSupported(Config.Scope config) {
return Profile.isFeatureEnabled(Profile.Feature.ACCOUNT_V3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,12 @@ private ClientModel getAccountManagementClient(RealmModel realm) {
}

private AccountResourceProvider getAccountResourceProvider(Theme theme) {
try {
if (theme.getProperties().containsKey(Theme.ACCOUNT_RESOURCE_PROVIDER_KEY)) {
return session.getProvider(AccountResourceProvider.class, theme.getProperties().getProperty(Theme.ACCOUNT_RESOURCE_PROVIDER_KEY));
try {
if (theme != null && theme.getProperties().containsKey(Theme.ACCOUNT_RESOURCE_PROVIDER_KEY)) {
return session.getProvider(AccountResourceProvider.class, theme.getProperties().getProperty(Theme.ACCOUNT_RESOURCE_PROVIDER_KEY));
}
} catch (IOException ignore) {
}
} catch (IOException ignore) {}
return session.getProvider(AccountResourceProvider.class);
return session.getProvider(AccountResourceProvider.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ public Theme getTheme(String name, Theme.Type type) {
if (theme == null) {
String defaultThemeName = session.getProvider(ThemeSelectorProvider.class).getDefaultThemeName(type);
theme = loadTheme(defaultThemeName, type, realm);
log.errorv("Failed to find {0} theme {1}, using built-in themes", type, name);
if (theme == null) {
log.warnv("Failed to find {0} theme {1}, as it might be unavailable because a required feature is disabled", type, name);
} else {
log.errorv("Failed to find {0} theme {1}, using built-in themes", type, name);
}
} else {
theme = factory.addCachedTheme(name, type, theme);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.keycloak.tests.account;

import java.io.IOException;

import org.keycloak.common.Profile;
import org.keycloak.testframework.annotations.InjectHttpClient;
import org.keycloak.testframework.annotations.InjectRealm;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.realm.ManagedRealm;
import org.keycloak.testframework.server.KeycloakServerConfig;
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

@KeycloakIntegrationTest(config = AccountConsoleDisabledTest.ServerConfig.class)
public class AccountConsoleDisabledTest {

@InjectRealm
ManagedRealm realm;

@InjectHttpClient
CloseableHttpClient httpClient;

@Test
public void accountConsoleReturns404WhenDisabled() throws IOException {
HttpGet request = new HttpGet(realm.getBaseUrl() + "/account/");

try (CloseableHttpResponse response = httpClient.execute(request)) {
assertEquals(404, response.getStatusLine().getStatusCode(),
"Account console should return 404 when ACCOUNT_V3 feature is disabled");
}
}

public static class ServerConfig implements KeycloakServerConfig {

@Override
public KeycloakServerConfigBuilder configure(KeycloakServerConfigBuilder config) {
return config.featuresDisabled(Profile.Feature.ACCOUNT_V3);
}
}
}
Loading