improvements: address feedback

This commit is contained in:
Scott Wilson
2025-01-31 11:01:54 -08:00
parent 59666740ca
commit 95d7c2082c
10 changed files with 100 additions and 14 deletions
@@ -249,7 +249,9 @@ export enum EventType {
DELETE_SECRET_SYNC = "delete-secret-sync", DELETE_SECRET_SYNC = "delete-secret-sync",
SECRET_SYNC_SYNC_SECRETS = "secret-sync-sync-secrets", SECRET_SYNC_SYNC_SECRETS = "secret-sync-sync-secrets",
SECRET_SYNC_IMPORT_SECRETS = "secret-sync-import-secrets", SECRET_SYNC_IMPORT_SECRETS = "secret-sync-import-secrets",
SECRET_SYNC_REMOVE_SECRETS = "secret-sync-remove-secrets" SECRET_SYNC_REMOVE_SECRETS = "secret-sync-remove-secrets",
OIDC_GROUP_MEMBERSHIP_MAPPING_ASSIGN_USER = "oidc-group-membership-mapping-assign-user",
OIDC_GROUP_MEMBERSHIP_MAPPING_REMOVE_USER = "oidc-group-membership-mapping-remove-user"
} }
interface UserActorMetadata { interface UserActorMetadata {
@@ -2044,6 +2046,26 @@ interface SecretSyncRemoveSecretsEvent {
}; };
} }
interface OidcGroupMembershipMappingAssignUserEvent {
type: EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_ASSIGN_USER;
metadata: {
assignedToGroups: { id: string; name: string }[];
userId: string;
userEmail: string;
userGroupsClaim: string[];
};
}
interface OidcGroupMembershipMappingRemoveUserEvent {
type: EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_REMOVE_USER;
metadata: {
removedFromGroups: { id: string; name: string }[];
userId: string;
userEmail: string;
userGroupsClaim: string[];
};
}
export type Event = export type Event =
| GetSecretsEvent | GetSecretsEvent
| GetSecretEvent | GetSecretEvent
@@ -2232,4 +2254,6 @@ export type Event =
| DeleteSecretSyncEvent | DeleteSecretSyncEvent
| SecretSyncSyncSecretsEvent | SecretSyncSyncSecretsEvent
| SecretSyncImportSecretsEvent | SecretSyncImportSecretsEvent
| SecretSyncRemoveSecretsEvent; | SecretSyncRemoveSecretsEvent
| OidcGroupMembershipMappingAssignUserEvent
| OidcGroupMembershipMappingRemoveUserEvent;
@@ -320,7 +320,10 @@ export const groupServiceFactory = ({
}); });
if (oidcConfig?.manageGroupMemberships) { if (oidcConfig?.manageGroupMemberships) {
throw new BadRequestError({ message: "Cannot add user to group: OIDC group membership mapping is enabled." }); throw new BadRequestError({
message:
"Cannot add user to group: OIDC group membership mapping is enabled - user must be assigned to this group in your OIDC provider."
});
} }
const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId); const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId);
@@ -385,7 +388,8 @@ export const groupServiceFactory = ({
if (oidcConfig?.manageGroupMemberships) { if (oidcConfig?.manageGroupMemberships) {
throw new BadRequestError({ throw new BadRequestError({
message: "Cannot remove user from group: OIDC group membership mapping is enabled." message:
"Cannot remove user from group: OIDC group membership mapping is enabled - user must be removed from this group in your OIDC provider."
}); });
} }
@@ -5,6 +5,8 @@ import { Issuer, Issuer as OpenIdIssuer, Strategy as OpenIdStrategy, TokenSet }
import { OrgMembershipStatus, SecretKeyEncoding, TableName, TUsers } from "@app/db/schemas"; import { OrgMembershipStatus, SecretKeyEncoding, TableName, TUsers } from "@app/db/schemas";
import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs"; import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal"; import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns"; import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal"; import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
@@ -22,7 +24,7 @@ import {
} from "@app/lib/crypto/encryption"; } from "@app/lib/crypto/encryption";
import { BadRequestError, ForbiddenRequestError, NotFoundError, OidcAuthError } from "@app/lib/errors"; import { BadRequestError, ForbiddenRequestError, NotFoundError, OidcAuthError } from "@app/lib/errors";
import { OrgServiceActor } from "@app/lib/types"; import { OrgServiceActor } from "@app/lib/types";
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type"; import { ActorType, AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service"; import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
import { TokenType } from "@app/services/auth-token/auth-token-types"; import { TokenType } from "@app/services/auth-token/auth-token-types";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal"; import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
@@ -88,6 +90,7 @@ type TOidcConfigServiceFactoryDep = {
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">; projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">;
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">; projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">; projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
auditLogService: Pick<TAuditLogServiceFactory, "createAuditLog">;
}; };
export type TOidcConfigServiceFactory = ReturnType<typeof oidcConfigServiceFactory>; export type TOidcConfigServiceFactory = ReturnType<typeof oidcConfigServiceFactory>;
@@ -108,7 +111,8 @@ export const oidcConfigServiceFactory = ({
groupProjectDAL, groupProjectDAL,
projectKeyDAL, projectKeyDAL,
projectDAL, projectDAL,
projectBotDAL projectBotDAL,
auditLogService
}: TOidcConfigServiceFactoryDep) => { }: TOidcConfigServiceFactoryDep) => {
const getOidc = async (dto: TGetOidcCfgDTO) => { const getOidc = async (dto: TGetOidcCfgDTO) => {
const org = await orgDAL.findOne({ slug: dto.orgSlug }); const org = await orgDAL.findOne({ slug: dto.orgSlug });
@@ -382,6 +386,25 @@ export const oidcConfigServiceFactory = ({
}); });
} }
if (groupsToAddUserTo.length) {
await auditLogService.createAuditLog({
actor: {
type: ActorType.PLATFORM,
metadata: {}
},
orgId,
event: {
type: EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_ASSIGN_USER,
metadata: {
userId: user.id,
userEmail: user.email ?? user.username,
assignedToGroups: groupsToAddUserTo.map(({ id, name }) => ({ id, name })),
userGroupsClaim: groups
}
}
});
}
const membershipsToRemove = userGroups const membershipsToRemove = userGroups
.filter((membership) => !groups.includes(membership.groupName)) .filter((membership) => !groups.includes(membership.groupName))
.map((membership) => membership.groupId); .map((membership) => membership.groupId);
@@ -397,6 +420,25 @@ export const oidcConfigServiceFactory = ({
projectKeyDAL projectKeyDAL
}); });
} }
if (groupsToRemoveUserFrom.length) {
await auditLogService.createAuditLog({
actor: {
type: ActorType.PLATFORM,
metadata: {}
},
orgId,
event: {
type: EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_REMOVE_USER,
metadata: {
userId: user.id,
userEmail: user.email ?? user.username,
removedFromGroups: groupsToRemoveUserFrom.map(({ id, name }) => ({ id, name })),
userGroupsClaim: groups
}
}
});
}
} }
await licenseService.updateSubscriptionOrgMemberCount(organization.id); await licenseService.updateSubscriptionOrgMemberCount(organization.id);
+2 -1
View File
@@ -1344,7 +1344,8 @@ export const registerRoutes = async (
projectDAL, projectDAL,
userGroupMembershipDAL, userGroupMembershipDAL,
groupProjectDAL, groupProjectDAL,
groupDAL groupDAL,
auditLogService
}); });
const userEngagementService = userEngagementServiceFactory({ const userEngagementService = userEngagementServiceFactory({
@@ -16,7 +16,8 @@ Infisical groups not present in their groups claim.
<Warning> <Warning>
Group membership changes in the Keycloak only sync with Infisical when a Group membership changes in the Keycloak only sync with Infisical when a
user logs in. For example, if you remove a user from a group in Keycloak, this change will not be reflected in Infisical until their next login. user logs in via OIDC. For example, if you remove a user from a group in Keycloak, this change will not be reflected in Infisical until their next OIDC login. To ensure this behavior, Infisical recommends enabling Enforce OIDC
SSO in the OIDC settings.
</Warning> </Warning>
@@ -114,7 +114,11 @@ export const eventToNameMap: { [K in EventType]: string } = {
[EventType.DELETE_SECRET_SYNC]: "Delete Secret Sync", [EventType.DELETE_SECRET_SYNC]: "Delete Secret Sync",
[EventType.SECRET_SYNC_SYNC_SECRETS]: "Secret Sync synced secrets", [EventType.SECRET_SYNC_SYNC_SECRETS]: "Secret Sync synced secrets",
[EventType.SECRET_SYNC_IMPORT_SECRETS]: "Secret Sync imported secrets", [EventType.SECRET_SYNC_IMPORT_SECRETS]: "Secret Sync imported secrets",
[EventType.SECRET_SYNC_REMOVE_SECRETS]: "Secret Sync removed secrets" [EventType.SECRET_SYNC_REMOVE_SECRETS]: "Secret Sync removed secrets",
[EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_ASSIGN_USER]:
"OIDC group membership mapping assigned user to groups",
[EventType.OIDC_GROUP_MEMBERSHIP_MAPPING_REMOVE_USER]:
"OIDC group membership mapping removed user from groups"
}; };
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = { export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
+3 -1
View File
@@ -127,5 +127,7 @@ export enum EventType {
DELETE_SECRET_SYNC = "delete-secret-sync", DELETE_SECRET_SYNC = "delete-secret-sync",
SECRET_SYNC_SYNC_SECRETS = "secret-sync-sync-secrets", SECRET_SYNC_SYNC_SECRETS = "secret-sync-sync-secrets",
SECRET_SYNC_IMPORT_SECRETS = "secret-sync-import-secrets", SECRET_SYNC_IMPORT_SECRETS = "secret-sync-import-secrets",
SECRET_SYNC_REMOVE_SECRETS = "secret-sync-remove-secrets" SECRET_SYNC_REMOVE_SECRETS = "secret-sync-remove-secrets",
OIDC_GROUP_MEMBERSHIP_MAPPING_ASSIGN_USER = "oidc-group-membership-mapping-assign-user",
OIDC_GROUP_MEMBERSHIP_MAPPING_REMOVE_USER = "oidc-group-membership-mapping-remove-user"
} }
@@ -40,6 +40,12 @@ export const LogsTableRow = ({ auditLog, isOrgAuditLogs, showActorColumn }: Prop
<p>Machine Identity</p> <p>Machine Identity</p>
</Td> </Td>
); );
case ActorType.PLATFORM:
return (
<Td>
<p>Platform</p>
</Td>
);
case ActorType.UNKNOWN_USER: case ActorType.UNKNOWN_USER:
return ( return (
<Td> <Td>
@@ -82,9 +82,9 @@ export const AddGroupMembersModal = ({ popUp, handlePopUpToggle }: Props) => {
text: "Successfully assigned user to the group", text: "Successfully assigned user to the group",
type: "success" type: "success"
}); });
} catch (error) { } catch {
createNotification({ createNotification({
text: (error as Error)?.message ?? "Failed to assign user to the group", text: "Failed to assign user to the group",
type: "error" type: "error"
}); });
} }
@@ -203,8 +203,10 @@ export const OrgOIDCSection = (): JSX.Element => {
<p className="mt-4 text-yellow"> <p className="mt-4 text-yellow">
<FontAwesomeIcon className="mr-1" icon={faWarning} /> <FontAwesomeIcon className="mr-1" icon={faWarning} />
Group membership changes in the OIDC provider only sync with Infisical when a Group membership changes in the OIDC provider only sync with Infisical when a
user logs in. For example, if you remove a user from a group in the OIDC user logs in via OIDC. For example, if you remove a user from a group in the
provider, this change will not be reflected in Infisical until their next login. OIDC provider, this change will not be reflected in Infisical until their next
OIDC login. To ensure this behavior, Infisical recommends enabling Enforce OIDC
SSO.
</p> </p>
</> </>
} }