Skip to content

Commit

Permalink
Temp service account warning
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Zaoral <[email protected]>
  • Loading branch information
Pepo48 committed Jul 17, 2024
1 parent f343c76 commit eaf180e
Show file tree
Hide file tree
Showing 11 changed files with 43 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class ClientRepresentation {
protected String baseUrl;
protected Boolean surrogateAuthRequired;
protected Boolean enabled;
protected Boolean temporaryAdminService;
protected Boolean alwaysDisplayInConsole;
protected String clientAuthenticatorType;
protected String secret;
Expand Down Expand Up @@ -130,6 +131,14 @@ public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public Boolean isTemporaryAdminService() {
return temporaryAdminService;
}

public void setTemporaryAdminService(Boolean temporaryAdminService) {
this.temporaryAdminService = temporaryAdminService;
}

public Boolean isAlwaysDisplayInConsole() {
return alwaysDisplayInConsole;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class UserRepresentation extends AbstractUserRepresentation{
protected String origin;
protected Long createdTimestamp;
protected Boolean enabled;
protected Boolean temporaryAdminUser;
protected Boolean totp;
protected String federationLink;
protected String serviceAccountClientId; // For rep, it points to clientId (not DB ID)
Expand All @@ -43,7 +44,6 @@ public class UserRepresentation extends AbstractUserRepresentation{
protected Map<String, List<String>> clientRoles;
protected List<UserConsentRepresentation> clientConsents;
protected Integer notBefore;
protected boolean temporaryAdmin;

@Deprecated
protected Map<String, List<String>> applicationRoles;
Expand Down Expand Up @@ -77,12 +77,12 @@ public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public boolean isTemporaryAdmin() {
return temporaryAdmin;
public Boolean isTemporaryAdminUser() {
return temporaryAdminUser;
}

public void setTemporaryAdmin(boolean temporaryAdmin) {
this.temporaryAdmin = temporaryAdmin;
public void setTemporaryAdminUser(Boolean temporaryAdminUser) {
this.temporaryAdminUser = temporaryAdminUser;
}

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3209,4 +3209,5 @@ forgotPasswordHelp=Specifies independent timeout for forgot password.
executeActionsHelp=Specifies independent timeout for execute actions.
validatingX509CertsHelp=The public certificates Keycloak uses to validate the signatures of SAML requests and responses from the external IDP when Use metadata descriptor URL is OFF. Multiple certificates can be entered separated by comma (,). The certificates can be re-imported from the Metadata descriptor URL clicking the Import Keys action in the identity provider page. The action downloads the current certificates in the metadata endpoint and assigns them to the config in this same option. You need to click Save to definitely store the re-imported certificates.
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
temporaryAdmin=Temporary admin user account. Ensure its replacement with a permanent admin user account as soon as possible.
temporaryService=Temporary admin service account. Ensure its replacement with a permanent admin service account as soon as possible.
9 changes: 9 additions & 0 deletions js/apps/admin-ui/src/clients/ClientsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {
Tab,
TabTitleText,
ToolbarItem,
Tooltip,
} from "@patternfly/react-core";
import {

Check failure on line 15 in js/apps/admin-ui/src/clients/ClientsSection.tsx

View workflow job for this annotation

GitHub Actions / Admin UI

Replace `⏎··WarningTriangleIcon,⏎` with `·WarningTriangleIcon·`
WarningTriangleIcon,
} from "@patternfly/react-icons";
import {
IFormatter,
IFormatterValueType,
Expand Down Expand Up @@ -71,6 +75,11 @@ const ClientDetailLink = (client: ClientRepresentation) => {
</Badge>
)}
</Link>
{client.temporaryAdminService && (
<Tooltip content={t("temporaryService")}>
<WarningTriangleIcon style={{ color: "gold" }} className="pf-v5-u-ml-sm"/>

Check failure on line 80 in js/apps/admin-ui/src/clients/ClientsSection.tsx

View workflow job for this annotation

GitHub Actions / Admin UI

Replace `·style={{·color:·"gold"·}}·className="pf-v5-u-ml-sm"` with `⏎············style={{·color:·"gold"·}}⏎············className="pf-v5-u-ml-sm"⏎··········`
</Tooltip>
)}
</TableText>
);
};
Expand Down
25 changes: 10 additions & 15 deletions js/apps/admin-ui/src/components/users/UserDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
Chip,
ChipGroup,
EmptyState,
Flex,
FlexItem,
Label,
Text,
Expand All @@ -23,7 +22,7 @@ import {
InfoCircleIcon,
WarningTriangleIcon,
} from "@patternfly/react-icons";
import type { IRowData } from "@patternfly/react-table";
import { TableText, type IRowData } from "@patternfly/react-table";

Check failure on line 25 in js/apps/admin-ui/src/components/users/UserDataTable.tsx

View workflow job for this annotation

GitHub Actions / Admin UI

'TableText' is defined but never used
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
Expand Down Expand Up @@ -52,20 +51,16 @@ const UserDetailLink = (user: BruteUser) => {
const { t } = useTranslation();
const { realm } = useRealm();
return (
<Flex spaceItems={{ default: "spaceItemsSm" }}>
{user.temporaryAdmin && (
<FlexItem>
<Label color="gold" icon={<InfoCircleIcon />}>
{t("temporaryAdmin")}
</Label>
</FlexItem>
<>
<Link to={toUser({ realm, id: user.id!, tab: "settings" })}>
{user.username}<StatusRow user={user}/>

Check failure on line 56 in js/apps/admin-ui/src/components/users/UserDataTable.tsx

View workflow job for this annotation

GitHub Actions / Admin UI

Replace `<StatusRow·user={user}` with `⏎········<StatusRow·user={user}·`
</Link>
{user.temporaryAdminUser && (
<Tooltip content={t("temporaryAdmin")}>
<WarningTriangleIcon style={{ color: "gold" }} className="pf-v5-u-ml-sm"/>

Check failure on line 60 in js/apps/admin-ui/src/components/users/UserDataTable.tsx

View workflow job for this annotation

GitHub Actions / Admin UI

Replace `·style={{·color:·"gold"·}}·className="pf-v5-u-ml-sm"` with `⏎············style={{·color:·"gold"·}}⏎············className="pf-v5-u-ml-sm"⏎··········`
</Tooltip>
)}
<FlexItem>
<Link to={toUser({ realm, id: user.id!, tab: "settings" })}>
{user.username} <StatusRow user={user} />
</Link>
</FlexItem>
</Flex>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default interface ClientRepresentation {
description?: string;
directAccessGrantsEnabled?: boolean;
enabled?: boolean;
temporaryAdminService?: boolean;
alwaysDisplayInConsole?: boolean;
frontchannelLogout?: boolean;
fullScopeAllowed?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default interface UserRepresentation {
enabled?: boolean;
totp?: boolean;
emailVerified?: boolean;
temporaryAdmin?: boolean;
temporaryAdminUser?: boolean;
disableableCredentialTypes?: string[];
requiredActions?: (RequiredActionAlias | string)[];
notBefore?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ private Stream<BruteUser> toRepresentation(RealmModel realm, UserPermissionEvalu
ModelToRepresentation.toBriefRepresentation(user) :
ModelToRepresentation.toRepresentation(session, realm, user);
userRep.setAccess(usersEvaluator.getAccess(user));
userRep.setTemporaryAdmin(Boolean.parseBoolean(user.getFirstAttribute(TEMP_ADMIN_ATTR_NAME)));
userRep.setTemporaryAdminUser(Boolean.parseBoolean(user.getFirstAttribute(TEMP_ADMIN_ATTR_NAME)));
return userRep;
}).map(this::getBruteForceStatus);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public BruteUser(UserRepresentation user) {
this.createdTimestamp = user.getCreatedTimestamp();
this.username = user.getUsername();
this.enabled = user.isEnabled();
this.temporaryAdmin = user.isTemporaryAdmin();
this.temporaryAdminUser = user.isTemporaryAdminUser();
this.totp = user.isTotp();
this.emailVerified = user.isEmailVerified();
this.firstName = user.getFirstName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,13 @@ public void createTemporaryMasterRealmAdminService(String clientId, String clien
adminClient.setSecret(clientSecret);

ClientModel adminClientModel = ClientManager.createClient(session, realm, adminClient);
adminClientModel.setAttribute(TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString());

new ClientManager(new RealmManager(session)).enableServiceAccount(adminClientModel);
UserModel serviceAccount = session.users().getServiceAccount(adminClientModel);
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
serviceAccount.grantRole(adminRole);

serviceAccount.setSingleAttribute(TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString());
// also set the expiration - could be relative to a creation timestamp, or computed

ServicesLogger.LOGGER.createdTemporaryAdminService(clientId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import java.util.stream.Stream;

import static java.lang.Boolean.TRUE;
import static org.keycloak.services.managers.ApplianceBootstrap.TEMP_ADMIN_ATTR_NAME;
import static org.keycloak.utils.StreamsUtil.paginatedStream;

/**
Expand Down Expand Up @@ -147,11 +148,13 @@ public Stream<ClientRepresentation> getClients(@Parameter(description = "filter
if (canView || auth.clients().canView(c)) {
representation = ModelToRepresentation.toRepresentation(c, session);
representation.setAccess(auth.clients().getAccess(c));
representation.setTemporaryAdminService(Boolean.parseBoolean(c.getAttribute(TEMP_ADMIN_ATTR_NAME)));
} else if (!viewableOnly && auth.clients().canView(c)) {
representation = new ClientRepresentation();
representation.setId(c.getId());
representation.setClientId(c.getClientId());
representation.setDescription(c.getDescription());
representation.setTemporaryAdminService(Boolean.parseBoolean(c.getAttribute(TEMP_ADMIN_ATTR_NAME)));
}

return representation;
Expand Down

0 comments on commit eaf180e

Please sign in to comment.