Warnings for temporary admin user and service account (#31387)
* UI banner, labels and log messages are shown when temporary admin account is used * added UI tests that check the elements' presence Signed-off-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
This commit is contained in:
parent
4675a4eda9
commit
1b5fe5437a
17 changed files with 175 additions and 16 deletions
2
.github/workflows/js-ci.yml
vendored
2
.github/workflows/js-ci.yml
vendored
|
@ -258,6 +258,8 @@ jobs:
|
||||||
env:
|
env:
|
||||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||||
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
||||||
|
KC_BOOTSTRAP_ADMIN_CLIENT_ID: temporary-admin-service
|
||||||
|
KC_BOOTSTRAP_ADMIN_CLIENT_SECRET: temporary-admin-service
|
||||||
|
|
||||||
- name: Start LDAP server
|
- name: Start LDAP server
|
||||||
run: pnpm --fail-if-no-match --filter ${{ env.WORKSPACE }} cy:ldap-server &
|
run: pnpm --fail-if-no-match --filter ${{ env.WORKSPACE }} cy:ldap-server &
|
||||||
|
|
|
@ -115,6 +115,24 @@ describe("Clients test", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should check temporary admin service label (non)existence", () => {
|
||||||
|
commonPage.sidebar().goToRealm("master");
|
||||||
|
commonPage.sidebar().goToClients();
|
||||||
|
commonPage
|
||||||
|
.tableToolbarUtils()
|
||||||
|
.searchItem("temporary-admin-service", false);
|
||||||
|
commonPage.tableUtils().checkRowItemExists("temporary-admin-service");
|
||||||
|
commonPage
|
||||||
|
.tableUtils()
|
||||||
|
.checkTemporaryAdminLabelExists("temporary-admin-label");
|
||||||
|
|
||||||
|
commonPage.tableToolbarUtils().searchItem("admin-cli", false);
|
||||||
|
commonPage.tableUtils().checkRowItemExists("admin-cli");
|
||||||
|
commonPage
|
||||||
|
.tableUtils()
|
||||||
|
.checkTemporaryAdminLabelExists("temporary-admin-label", false);
|
||||||
|
});
|
||||||
|
|
||||||
it("Should list client scopes", () => {
|
it("Should list client scopes", () => {
|
||||||
commonPage
|
commonPage
|
||||||
.tableUtils()
|
.tableUtils()
|
||||||
|
|
|
@ -78,6 +78,22 @@ describe("User creation", () => {
|
||||||
masthead.checkNotificationMessage("The user has been created");
|
masthead.checkNotificationMessage("The user has been created");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should check temporary admin user existence", () => {
|
||||||
|
const commonPage = new CommonPage();
|
||||||
|
|
||||||
|
// check banner visibility first
|
||||||
|
cy.get(".pf-v5-c-banner").should(
|
||||||
|
"contain.text",
|
||||||
|
"You are logged in as a temporary admin user.",
|
||||||
|
);
|
||||||
|
|
||||||
|
commonPage.tableToolbarUtils().searchItem("admin", false);
|
||||||
|
commonPage.tableUtils().checkRowItemExists("admin");
|
||||||
|
commonPage
|
||||||
|
.tableUtils()
|
||||||
|
.checkTemporaryAdminLabelExists("temporary-admin-label");
|
||||||
|
});
|
||||||
|
|
||||||
it("Create user with groups test", () => {
|
it("Create user with groups test", () => {
|
||||||
itemIdWithGroups += uuid();
|
itemIdWithGroups += uuid();
|
||||||
// Add user from search bar
|
// Add user from search bar
|
||||||
|
|
|
@ -148,6 +148,16 @@ export default class TablePage extends CommonElements {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkTemporaryAdminLabelExists(labelId: string, exist = true) {
|
||||||
|
cy.get(
|
||||||
|
(this.#tableInModal ? ".pf-v5-c-modal-box.pf-m-md " : "") +
|
||||||
|
this.#tableRowItem,
|
||||||
|
)
|
||||||
|
.find(`#${labelId}`)
|
||||||
|
.should((!exist ? "not." : "") + "exist");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
checkRowItemValueByItemName(itemName: string, column: number, value: string) {
|
checkRowItemValueByItemName(itemName: string, column: number, value: string) {
|
||||||
cy.get(
|
cy.get(
|
||||||
(this.#tableInModal ? ".pf-v5-c-modal-box.pf-m-md " : "") +
|
(this.#tableInModal ? ".pf-v5-c-modal-box.pf-m-md " : "") +
|
||||||
|
|
|
@ -3237,3 +3237,6 @@ userInvitedOrganization_one=Invite to user sent
|
||||||
userInvitedOrganizationError=Could not invite user to the organizations\: {{error}}
|
userInvitedOrganizationError=Could not invite user to the organizations\: {{error}}
|
||||||
userInvitedOrganization_other={{count}} invites to users sent
|
userInvitedOrganization_other={{count}} invites to users sent
|
||||||
sentInvitation=Sent invitation
|
sentInvitation=Sent invitation
|
||||||
|
loggedInAsTempAdminUser=You are logged in as a temporary admin user. To harden security, create a permanent admin account and delete the temporary one.
|
||||||
|
temporaryAdmin=Temporary admin user account. Ensure it is replaced with a permanent admin user account as soon as possible.
|
||||||
|
temporaryService=Temporary admin service account. Ensure it is replaced with a permanent admin service account as soon as possible.
|
|
@ -25,6 +25,7 @@ import { WhoAmIContextProvider } from "./context/whoami/WhoAmI";
|
||||||
import type { Environment } from "./environment";
|
import type { Environment } from "./environment";
|
||||||
import { SubGroups } from "./groups/SubGroupsContext";
|
import { SubGroups } from "./groups/SubGroupsContext";
|
||||||
import { AuthWall } from "./root/AuthWall";
|
import { AuthWall } from "./root/AuthWall";
|
||||||
|
import { Banners } from "./Banners";
|
||||||
|
|
||||||
const AppContexts = ({ children }: PropsWithChildren) => (
|
const AppContexts = ({ children }: PropsWithChildren) => (
|
||||||
<ErrorBoundaryProvider>
|
<ErrorBoundaryProvider>
|
||||||
|
@ -65,6 +66,7 @@ export const App = () => {
|
||||||
breadcrumb={<PageBreadCrumbs />}
|
breadcrumb={<PageBreadCrumbs />}
|
||||||
mainContainerId={mainPageContentId}
|
mainContainerId={mainPageContentId}
|
||||||
>
|
>
|
||||||
|
<Banners />
|
||||||
<ErrorBoundaryFallback fallback={ErrorRenderer}>
|
<ErrorBoundaryFallback fallback={ErrorRenderer}>
|
||||||
<Suspense fallback={<KeycloakSpinner />}>
|
<Suspense fallback={<KeycloakSpinner />}>
|
||||||
<AuthWall>
|
<AuthWall>
|
||||||
|
|
26
js/apps/admin-ui/src/Banners.tsx
Normal file
26
js/apps/admin-ui/src/Banners.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { Banner, Flex, FlexItem } from "@patternfly/react-core";
|
||||||
|
import { ExclamationTriangleIcon } from "@patternfly/react-icons";
|
||||||
|
import { useWhoAmI } from "./context/whoami/WhoAmI";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const WarnBanner = (msg: string) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Banner screenReaderText={t(msg)} variant="gold" isSticky>
|
||||||
|
<Flex spaceItems={{ default: "spaceItemsSm" }}>
|
||||||
|
<FlexItem>
|
||||||
|
<ExclamationTriangleIcon />
|
||||||
|
</FlexItem>
|
||||||
|
<FlexItem>{t(msg)}</FlexItem>
|
||||||
|
</Flex>
|
||||||
|
</Banner>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Banners = () => {
|
||||||
|
const { whoAmI } = useWhoAmI();
|
||||||
|
|
||||||
|
if (whoAmI.isTemporary()) return WarnBanner("loggedInAsTempAdminUser");
|
||||||
|
// more banners in the future?
|
||||||
|
};
|
|
@ -10,7 +10,9 @@ import {
|
||||||
Tab,
|
Tab,
|
||||||
TabTitleText,
|
TabTitleText,
|
||||||
ToolbarItem,
|
ToolbarItem,
|
||||||
|
Tooltip,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
|
import { WarningTriangleIcon } from "@patternfly/react-icons";
|
||||||
import { IRowData, TableText, cellWidth } from "@patternfly/react-table";
|
import { IRowData, TableText, cellWidth } from "@patternfly/react-table";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
@ -58,6 +60,14 @@ const ClientDetailLink = (client: ClientRepresentation) => {
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
|
{client.attributes?.["is_temporary_admin"] === "true" && (
|
||||||
|
<Tooltip content={t("temporaryService")}>
|
||||||
|
<WarningTriangleIcon
|
||||||
|
className="pf-v5-u-ml-sm"
|
||||||
|
id="temporary-admin-label"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</TableText>
|
</TableText>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,11 +48,23 @@ export type UserAttribute = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserDetailLink = (user: BruteUser) => {
|
const UserDetailLink = (user: BruteUser) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { realm } = useRealm();
|
const { realm } = useRealm();
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Link to={toUser({ realm, id: user.id!, tab: "settings" })}>
|
<Link to={toUser({ realm, id: user.id!, tab: "settings" })}>
|
||||||
{user.username} <StatusRow user={user} />
|
{user.username}
|
||||||
|
<StatusRow user={user} />
|
||||||
</Link>
|
</Link>
|
||||||
|
{user.attributes?.["is_temporary_admin"][0] === "true" && (
|
||||||
|
<Tooltip content={t("temporaryAdmin")}>
|
||||||
|
<WarningTriangleIcon
|
||||||
|
className="pf-v5-u-ml-sm"
|
||||||
|
id="temporary-admin-label"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@ export class WhoAmI {
|
||||||
|
|
||||||
return this.#me.realm_access;
|
return this.#me.realm_access;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isTemporary(): boolean {
|
||||||
|
return this.#me?.temporary ?? false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type WhoAmIProps = {
|
type WhoAmIProps = {
|
||||||
|
|
|
@ -16,6 +16,8 @@ const LOCAL_DIST_NAME = "keycloak-999.0.0-SNAPSHOT.tar.gz";
|
||||||
const SCRIPT_EXTENSION = process.platform === "win32" ? ".bat" : ".sh";
|
const SCRIPT_EXTENSION = process.platform === "win32" ? ".bat" : ".sh";
|
||||||
const ADMIN_USERNAME = "admin";
|
const ADMIN_USERNAME = "admin";
|
||||||
const ADMIN_PASSWORD = "admin";
|
const ADMIN_PASSWORD = "admin";
|
||||||
|
const CLIENT_ID = "temporary-admin-service";
|
||||||
|
const CLIENT_SECRET = "temporary-admin-service";
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
local: {
|
local: {
|
||||||
|
@ -39,6 +41,8 @@ async function startServer() {
|
||||||
const env = {
|
const env = {
|
||||||
KC_BOOTSTRAP_ADMIN_USERNAME: ADMIN_USERNAME,
|
KC_BOOTSTRAP_ADMIN_USERNAME: ADMIN_USERNAME,
|
||||||
KC_BOOTSTRAP_ADMIN_PASSWORD: ADMIN_PASSWORD,
|
KC_BOOTSTRAP_ADMIN_PASSWORD: ADMIN_PASSWORD,
|
||||||
|
KC_BOOTSTRAP_ADMIN_CLIENT_ID: CLIENT_ID,
|
||||||
|
KC_BOOTSTRAP_ADMIN_CLIENT_SECRET: CLIENT_SECRET,
|
||||||
...process.env,
|
...process.env,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,5 @@ export default interface WhoAmIRepresentation {
|
||||||
locale: string;
|
locale: string;
|
||||||
createRealm: boolean;
|
createRealm: boolean;
|
||||||
realm_access: { [key: string]: AccessType[] };
|
realm_access: { [key: string]: AccessType[] };
|
||||||
|
temporary: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,4 +184,7 @@ public final class Constants {
|
||||||
|
|
||||||
//attribute name used to mark a client as realm client
|
//attribute name used to mark a client as realm client
|
||||||
public static final String REALM_CLIENT = "realm_client";
|
public static final String REALM_CLIENT = "realm_client";
|
||||||
|
|
||||||
|
//attribute name used to mark a temporary admin user/service account as temporary
|
||||||
|
public static final String IS_TEMP_ADMIN_ATTR_NAME = "is_temporary_admin";
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser;
|
import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser;
|
||||||
|
import static org.keycloak.models.Constants.IS_TEMP_ADMIN_ATTR_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -263,10 +264,21 @@ public class ModelToRepresentation {
|
||||||
rep.setEnabled(user.isEnabled());
|
rep.setEnabled(user.isEnabled());
|
||||||
rep.setEmailVerified(user.isEmailVerified());
|
rep.setEmailVerified(user.isEmailVerified());
|
||||||
rep.setFederationLink(user.getFederationLink());
|
rep.setFederationLink(user.getFederationLink());
|
||||||
|
addAttributeToBriefRep(user, rep, IS_TEMP_ADMIN_ATTR_NAME);
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addAttributeToBriefRep(UserModel user, UserRepresentation userRep, String attributeName) {
|
||||||
|
String userAttributeValue = user.getFirstAttribute(attributeName);
|
||||||
|
if (userAttributeValue != null) {
|
||||||
|
if (userRep.getAttributes() == null) {
|
||||||
|
userRep.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
userRep.getAttributes().put(attributeName, Collections.singletonList(userAttributeValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static EventRepresentation toRepresentation(Event event) {
|
public static EventRepresentation toRepresentation(Event event) {
|
||||||
EventRepresentation rep = new EventRepresentation();
|
EventRepresentation rep = new EventRepresentation();
|
||||||
rep.setTime(event.getTime());
|
rep.setTime(event.getTime());
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.keycloak.events.log;
|
package org.keycloak.events.log;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.common.util.StackUtil;
|
import org.keycloak.common.util.StackUtil;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.events.Event;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.events.EventListenerProvider;
|
||||||
|
@ -25,6 +26,7 @@ import org.keycloak.events.EventListenerTransaction;
|
||||||
import org.keycloak.events.admin.AdminEvent;
|
import org.keycloak.events.admin.AdminEvent;
|
||||||
import org.keycloak.models.KeycloakContext;
|
import org.keycloak.models.KeycloakContext;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
import org.keycloak.utils.StringUtil;
|
import org.keycloak.utils.StringUtil;
|
||||||
|
|
||||||
|
@ -32,6 +34,9 @@ import jakarta.ws.rs.core.Cookie;
|
||||||
import jakarta.ws.rs.core.HttpHeaders;
|
import jakarta.ws.rs.core.HttpHeaders;
|
||||||
import jakarta.ws.rs.core.UriInfo;
|
import jakarta.ws.rs.core.UriInfo;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static org.keycloak.models.Constants.IS_TEMP_ADMIN_ATTR_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -135,6 +140,24 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider
|
||||||
|
|
||||||
logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
|
logger.log(logger.isTraceEnabled() ? Logger.Level.TRACE : level, sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.getRealmName().equals(Config.getAdminRealm())) {
|
||||||
|
Supplier<RealmModel> getRealm = () -> session.realms().getRealm(event.getRealmId());
|
||||||
|
switch (event.getType()) {
|
||||||
|
case LOGIN:
|
||||||
|
var user = session.users().getUserById(getRealm.get(), event.getUserId());
|
||||||
|
if (Boolean.parseBoolean(user.getFirstAttribute(IS_TEMP_ADMIN_ATTR_NAME))) {
|
||||||
|
logger.warn(user.getUsername() + " is a temporary admin user account. To harden security, create a permanent account and delete the temporary one.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CLIENT_LOGIN:
|
||||||
|
var client = session.clients().getClientByClientId(getRealm.get(), event.getClientId());
|
||||||
|
if (Boolean.parseBoolean(client.getAttribute(IS_TEMP_ADMIN_ATTR_NAME))) {
|
||||||
|
logger.warn(client.getClientId() + " is a temporary admin service account. To harden security, create a permanent account and delete the temporary one.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
|
private void logAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
|
||||||
|
|
|
@ -37,6 +37,8 @@ import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.userprofile.UserProfileProvider;
|
import org.keycloak.userprofile.UserProfileProvider;
|
||||||
import org.keycloak.utils.StringUtil;
|
import org.keycloak.utils.StringUtil;
|
||||||
|
|
||||||
|
import static org.keycloak.models.Constants.IS_TEMP_ADMIN_ATTR_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -136,8 +138,7 @@ public class ApplianceBootstrap {
|
||||||
try {
|
try {
|
||||||
UserModel adminUser = session.users().addUser(realm, username);
|
UserModel adminUser = session.users().addUser(realm, username);
|
||||||
adminUser.setEnabled(true);
|
adminUser.setEnabled(true);
|
||||||
// TODO: is this appropriate, does it need to be managed?
|
adminUser.setSingleAttribute(IS_TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString());
|
||||||
// adminUser.setSingleAttribute("temporary_admin", Boolean.TRUE.toString());
|
|
||||||
// also set the expiration - could be relative to a creation timestamp, or computed
|
// also set the expiration - could be relative to a creation timestamp, or computed
|
||||||
|
|
||||||
UserCredentialModel usrCredModel = UserCredentialModel.password(password);
|
UserCredentialModel usrCredModel = UserCredentialModel.password(password);
|
||||||
|
@ -182,7 +183,7 @@ public class ApplianceBootstrap {
|
||||||
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||||
serviceAccount.grantRole(adminRole);
|
serviceAccount.grantRole(adminRole);
|
||||||
|
|
||||||
// TODO: set temporary
|
adminClientModel.setAttribute(IS_TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString());
|
||||||
// also set the expiration - could be relative to a creation timestamp, or computed
|
// also set the expiration - could be relative to a creation timestamp, or computed
|
||||||
|
|
||||||
ServicesLogger.LOGGER.createdTemporaryAdminService(clientId);
|
ServicesLogger.LOGGER.createdTemporaryAdminService(clientId);
|
||||||
|
|
|
@ -68,6 +68,8 @@ import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.keycloak.models.Constants.IS_TEMP_ADMIN_ATTR_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -98,6 +100,7 @@ public class AdminConsole {
|
||||||
protected String realm;
|
protected String realm;
|
||||||
protected String displayName;
|
protected String displayName;
|
||||||
protected Locale locale;
|
protected Locale locale;
|
||||||
|
protected boolean isTemporary;
|
||||||
|
|
||||||
@JsonProperty("createRealm")
|
@JsonProperty("createRealm")
|
||||||
protected boolean createRealm;
|
protected boolean createRealm;
|
||||||
|
@ -107,13 +110,14 @@ public class AdminConsole {
|
||||||
public WhoAmI() {
|
public WhoAmI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess, Locale locale) {
|
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess, Locale locale, boolean isTemporary) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.createRealm = createRealm;
|
this.createRealm = createRealm;
|
||||||
this.realmAccess = realmAccess;
|
this.realmAccess = realmAccess;
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
|
this.isTemporary = isTemporary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
|
@ -168,6 +172,14 @@ public class AdminConsole {
|
||||||
public String getLocaleLanguageTag() {
|
public String getLocaleLanguageTag() {
|
||||||
return locale != null ? locale.toLanguageTag() : null;
|
return locale != null ? locale.toLanguageTag() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isTemporary() {
|
||||||
|
return isTemporary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemporary(boolean temporary) {
|
||||||
|
isTemporary = temporary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -269,7 +281,7 @@ public class AdminConsole {
|
||||||
.allowedOrigins(authResult.getToken())
|
.allowedOrigins(authResult.getToken())
|
||||||
.allowedMethods("GET")
|
.allowedMethods("GET")
|
||||||
.auth()
|
.auth()
|
||||||
.add(Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess, locale)));
|
.add(Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess, locale, Boolean.parseBoolean(user.getFirstAttribute(IS_TEMP_ADMIN_ATTR_NAME)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
|
private void addRealmAccess(RealmModel realm, UserModel user, Map<String, Set<String>> realmAdminAccess) {
|
||||||
|
|
Loading…
Reference in a new issue