refactor(sso): standardize SSO identity provider query names (#10335)
Updated method, query, and variable names to align with a consistent naming convention for fetching SSO identity providers. Added comprehensive unit tests to validate SSO service logic, ensuring better reliability and maintainability. --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
/* eslint-disable */
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
import { PermissionsOnAllObjectRecords } from 'twenty-shared';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
@ -33,6 +32,33 @@ export type ActivateWorkspaceInput = {
|
||||
displayName?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type AdminPanelHealthServiceData = {
|
||||
__typename?: 'AdminPanelHealthServiceData';
|
||||
details?: Maybe<Scalars['String']['output']>;
|
||||
queues?: Maybe<Array<AdminPanelWorkerQueueHealth>>;
|
||||
status: AdminPanelHealthServiceStatus;
|
||||
};
|
||||
|
||||
export enum AdminPanelHealthServiceStatus {
|
||||
OPERATIONAL = 'OPERATIONAL',
|
||||
OUTAGE = 'OUTAGE'
|
||||
}
|
||||
|
||||
export enum AdminPanelIndicatorHealthStatusInputEnum {
|
||||
DATABASE = 'DATABASE',
|
||||
MESSAGE_SYNC = 'MESSAGE_SYNC',
|
||||
REDIS = 'REDIS',
|
||||
WORKER = 'WORKER'
|
||||
}
|
||||
|
||||
export type AdminPanelWorkerQueueHealth = {
|
||||
__typename?: 'AdminPanelWorkerQueueHealth';
|
||||
metrics: WorkerQueueMetrics;
|
||||
name: Scalars['String']['output'];
|
||||
status: AdminPanelHealthServiceStatus;
|
||||
workers: Scalars['Float']['output'];
|
||||
};
|
||||
|
||||
export type Analytics = {
|
||||
__typename?: 'Analytics';
|
||||
/** Boolean that confirms query was dispatched */
|
||||
@ -257,6 +283,7 @@ export type ClientConfig = {
|
||||
debugMode: Scalars['Boolean']['output'];
|
||||
defaultSubdomain?: Maybe<Scalars['String']['output']>;
|
||||
frontDomain: Scalars['String']['output'];
|
||||
isAttachmentPreviewEnabled: Scalars['Boolean']['output'];
|
||||
isEmailVerificationRequired: Scalars['Boolean']['output'];
|
||||
isGoogleCalendarEnabled: Scalars['Boolean']['output'];
|
||||
isGoogleMessagingEnabled: Scalars['Boolean']['output'];
|
||||
@ -809,6 +836,7 @@ export type Mutation = {
|
||||
activateWorkspace: Workspace;
|
||||
authorizeApp: AuthorizeApp;
|
||||
buildDraftServerlessFunction: ServerlessFunction;
|
||||
checkCustomDomainValidRecords?: Maybe<CustomDomainValidRecords>;
|
||||
checkoutSession: BillingSessionOutput;
|
||||
computeStepOutputSchema: Scalars['JSON']['output'];
|
||||
createDraftFromWorkflowVersion: WorkflowVersion;
|
||||
@ -1305,6 +1333,13 @@ export type PageInfo = {
|
||||
startCursor?: Maybe<Scalars['ConnectionCursor']['output']>;
|
||||
};
|
||||
|
||||
export enum PermissionsOnAllObjectRecords {
|
||||
DESTROY_ALL_OBJECT_RECORDS = 'DESTROY_ALL_OBJECT_RECORDS',
|
||||
READ_ALL_OBJECT_RECORDS = 'READ_ALL_OBJECT_RECORDS',
|
||||
SOFT_DELETE_ALL_OBJECT_RECORDS = 'SOFT_DELETE_ALL_OBJECT_RECORDS',
|
||||
UPDATE_ALL_OBJECT_RECORDS = 'UPDATE_ALL_OBJECT_RECORDS'
|
||||
}
|
||||
|
||||
export type PostgresCredentials = {
|
||||
__typename?: 'PostgresCredentials';
|
||||
id: Scalars['UUID']['output'];
|
||||
@ -1343,7 +1378,6 @@ export type PublishServerlessFunctionInput = {
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
billingPortalSession: BillingSessionOutput;
|
||||
checkCustomDomainValidRecords?: Maybe<CustomDomainValidRecords>;
|
||||
checkUserExists: UserExistsOutput;
|
||||
checkWorkspaceInviteHashIsValid: WorkspaceInviteHashValid;
|
||||
clientConfig: ClientConfig;
|
||||
@ -1361,18 +1395,20 @@ export type Query = {
|
||||
findWorkspaceInvitations: Array<WorkspaceInvitation>;
|
||||
getAvailablePackages: Scalars['JSON']['output'];
|
||||
getEnvironmentVariablesGrouped: EnvironmentVariablesOutput;
|
||||
getIndicatorHealthStatus: AdminPanelHealthServiceData;
|
||||
getPostgresCredentials?: Maybe<PostgresCredentials>;
|
||||
getProductPrices: BillingProductPricesOutput;
|
||||
getPublicWorkspaceDataByDomain: PublicWorkspaceDataOutput;
|
||||
getRoles: Array<Role>;
|
||||
getSSOIdentityProviders: Array<FindAvailableSsoidpOutput>;
|
||||
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']['output']>;
|
||||
getSystemHealthStatus: SystemHealth;
|
||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||
getTimelineThreadsFromCompanyId: TimelineThreadsWithTotal;
|
||||
getTimelineThreadsFromPersonId: TimelineThreadsWithTotal;
|
||||
index: Index;
|
||||
indexMetadatas: IndexConnection;
|
||||
listSSOIdentityProvidersByWorkspaceId: Array<FindAvailableSsoidpOutput>;
|
||||
object: Object;
|
||||
objects: ObjectConnection;
|
||||
plans: Array<BillingPlanOutput>;
|
||||
@ -1443,6 +1479,11 @@ export type QueryGetAvailablePackagesArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetIndicatorHealthStatusArgs = {
|
||||
indicatorName: AdminPanelIndicatorHealthStatusInputEnum;
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetProductPricesArgs = {
|
||||
product: Scalars['String']['input'];
|
||||
};
|
||||
@ -1633,6 +1674,10 @@ export type ResendEmailVerificationTokenOutput = {
|
||||
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
canDestroyAllObjectRecords: Scalars['Boolean']['output'];
|
||||
canReadAllObjectRecords: Scalars['Boolean']['output'];
|
||||
canSoftDeleteAllObjectRecords: Scalars['Boolean']['output'];
|
||||
canUpdateAllObjectRecords: Scalars['Boolean']['output'];
|
||||
canUpdateAllSettings: Scalars['Boolean']['output'];
|
||||
description?: Maybe<Scalars['String']['output']>;
|
||||
id: Scalars['String']['output'];
|
||||
@ -1798,6 +1843,14 @@ export type Support = {
|
||||
supportFrontChatId?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type SystemHealth = {
|
||||
__typename?: 'SystemHealth';
|
||||
database: AdminPanelHealthServiceData;
|
||||
messageSync: AdminPanelHealthServiceData;
|
||||
redis: AdminPanelHealthServiceData;
|
||||
worker: AdminPanelHealthServiceData;
|
||||
};
|
||||
|
||||
export type TimelineCalendarEvent = {
|
||||
__typename?: 'TimelineCalendarEvent';
|
||||
conferenceLink: LinksMetadata;
|
||||
@ -2050,8 +2103,8 @@ export type UserWorkspace = {
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
deletedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
id: Scalars['UUID']['output'];
|
||||
settingsPermissions?: Maybe<Array<SettingsFeatures>>;
|
||||
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
|
||||
settingsPermissions?: Maybe<Array<SettingsFeatures>>;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
user: User;
|
||||
userId: Scalars['String']['output'];
|
||||
@ -2065,6 +2118,16 @@ export type ValidatePasswordResetToken = {
|
||||
id: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type WorkerQueueMetrics = {
|
||||
__typename?: 'WorkerQueueMetrics';
|
||||
active: Scalars['Float']['output'];
|
||||
completed: Scalars['Float']['output'];
|
||||
delayed: Scalars['Float']['output'];
|
||||
failed: Scalars['Float']['output'];
|
||||
prioritized: Scalars['Float']['output'];
|
||||
waiting: Scalars['Float']['output'];
|
||||
};
|
||||
|
||||
export type WorkflowAction = {
|
||||
__typename?: 'WorkflowAction';
|
||||
id: Scalars['UUID']['output'];
|
||||
|
||||
@ -1264,6 +1264,7 @@ export type Query = {
|
||||
getProductPrices: BillingProductPricesOutput;
|
||||
getPublicWorkspaceDataByDomain: PublicWorkspaceDataOutput;
|
||||
getRoles: Array<Role>;
|
||||
getSSOIdentityProviders: Array<FindAvailableSsoidpOutput>;
|
||||
getServerlessFunctionSourceCode?: Maybe<Scalars['JSON']>;
|
||||
getSystemHealthStatus: SystemHealth;
|
||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||
@ -1272,7 +1273,6 @@ export type Query = {
|
||||
getTimelineThreadsFromPersonId: TimelineThreadsWithTotal;
|
||||
index: Index;
|
||||
indexMetadatas: IndexConnection;
|
||||
listSSOIdentityProvidersByWorkspaceId: Array<FindAvailableSsoidpOutput>;
|
||||
object: Object;
|
||||
objects: ObjectConnection;
|
||||
plans: Array<BillingPlanOutput>;
|
||||
@ -2364,10 +2364,10 @@ export type EditSsoIdentityProviderMutationVariables = Exact<{
|
||||
|
||||
export type EditSsoIdentityProviderMutation = { __typename?: 'Mutation', editSSOIdentityProvider: { __typename?: 'EditSsoOutput', id: string, type: IdentityProviderType, issuer: string, name: string, status: SsoIdentityProviderStatus } };
|
||||
|
||||
export type ListSsoIdentityProvidersByWorkspaceIdQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
export type GetSsoIdentityProvidersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ListSsoIdentityProvidersByWorkspaceIdQuery = { __typename?: 'Query', listSSOIdentityProvidersByWorkspaceId: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
|
||||
export type GetSsoIdentityProvidersQuery = { __typename?: 'Query', getSSOIdentityProviders: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
|
||||
|
||||
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingsFeatures> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }> } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> };
|
||||
|
||||
@ -4392,9 +4392,9 @@ export function useEditSsoIdentityProviderMutation(baseOptions?: Apollo.Mutation
|
||||
export type EditSsoIdentityProviderMutationHookResult = ReturnType<typeof useEditSsoIdentityProviderMutation>;
|
||||
export type EditSsoIdentityProviderMutationResult = Apollo.MutationResult<EditSsoIdentityProviderMutation>;
|
||||
export type EditSsoIdentityProviderMutationOptions = Apollo.BaseMutationOptions<EditSsoIdentityProviderMutation, EditSsoIdentityProviderMutationVariables>;
|
||||
export const ListSsoIdentityProvidersByWorkspaceIdDocument = gql`
|
||||
query ListSSOIdentityProvidersByWorkspaceId {
|
||||
listSSOIdentityProvidersByWorkspaceId {
|
||||
export const GetSsoIdentityProvidersDocument = gql`
|
||||
query GetSSOIdentityProviders {
|
||||
getSSOIdentityProviders {
|
||||
type
|
||||
id
|
||||
name
|
||||
@ -4405,31 +4405,31 @@ export const ListSsoIdentityProvidersByWorkspaceIdDocument = gql`
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useListSsoIdentityProvidersByWorkspaceIdQuery__
|
||||
* __useGetSsoIdentityProvidersQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useListSsoIdentityProvidersByWorkspaceIdQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useListSsoIdentityProvidersByWorkspaceIdQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* To run a query within a React component, call `useGetSsoIdentityProvidersQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetSsoIdentityProvidersQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||
*
|
||||
* @example
|
||||
* const { data, loading, error } = useListSsoIdentityProvidersByWorkspaceIdQuery({
|
||||
* const { data, loading, error } = useGetSsoIdentityProvidersQuery({
|
||||
* variables: {
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useListSsoIdentityProvidersByWorkspaceIdQuery(baseOptions?: Apollo.QueryHookOptions<ListSsoIdentityProvidersByWorkspaceIdQuery, ListSsoIdentityProvidersByWorkspaceIdQueryVariables>) {
|
||||
export function useGetSsoIdentityProvidersQuery(baseOptions?: Apollo.QueryHookOptions<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<ListSsoIdentityProvidersByWorkspaceIdQuery, ListSsoIdentityProvidersByWorkspaceIdQueryVariables>(ListSsoIdentityProvidersByWorkspaceIdDocument, options);
|
||||
return Apollo.useQuery<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>(GetSsoIdentityProvidersDocument, options);
|
||||
}
|
||||
export function useListSsoIdentityProvidersByWorkspaceIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ListSsoIdentityProvidersByWorkspaceIdQuery, ListSsoIdentityProvidersByWorkspaceIdQueryVariables>) {
|
||||
export function useGetSsoIdentityProvidersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<ListSsoIdentityProvidersByWorkspaceIdQuery, ListSsoIdentityProvidersByWorkspaceIdQueryVariables>(ListSsoIdentityProvidersByWorkspaceIdDocument, options);
|
||||
return Apollo.useLazyQuery<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>(GetSsoIdentityProvidersDocument, options);
|
||||
}
|
||||
export type ListSsoIdentityProvidersByWorkspaceIdQueryHookResult = ReturnType<typeof useListSsoIdentityProvidersByWorkspaceIdQuery>;
|
||||
export type ListSsoIdentityProvidersByWorkspaceIdLazyQueryHookResult = ReturnType<typeof useListSsoIdentityProvidersByWorkspaceIdLazyQuery>;
|
||||
export type ListSsoIdentityProvidersByWorkspaceIdQueryResult = Apollo.QueryResult<ListSsoIdentityProvidersByWorkspaceIdQuery, ListSsoIdentityProvidersByWorkspaceIdQueryVariables>;
|
||||
export type GetSsoIdentityProvidersQueryHookResult = ReturnType<typeof useGetSsoIdentityProvidersQuery>;
|
||||
export type GetSsoIdentityProvidersLazyQueryHookResult = ReturnType<typeof useGetSsoIdentityProvidersLazyQuery>;
|
||||
export type GetSsoIdentityProvidersQueryResult = Apollo.QueryResult<GetSsoIdentityProvidersQuery, GetSsoIdentityProvidersQueryVariables>;
|
||||
export const DeleteUserAccountDocument = gql`
|
||||
mutation DeleteUserAccount {
|
||||
deleteUser {
|
||||
|
||||
@ -49,7 +49,6 @@ export const SettingsAccountsRowDropdownMenu = ({
|
||||
<>
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
className={className}
|
||||
dropdownPlacement="right-start"
|
||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||
clickableComponent={
|
||||
|
||||
@ -15,7 +15,7 @@ import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { IconKey } from 'twenty-ui';
|
||||
import { useListSsoIdentityProvidersByWorkspaceIdQuery } from '~/generated/graphql';
|
||||
import { useGetSsoIdentityProvidersQuery } from '~/generated/graphql';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
|
||||
const StyledLink = styled(Link, {
|
||||
@ -36,13 +36,11 @@ export const SettingsSSOIdentitiesProvidersListCard = () => {
|
||||
SSOIdentitiesProvidersState,
|
||||
);
|
||||
|
||||
const { loading } = useListSsoIdentityProvidersByWorkspaceIdQuery({
|
||||
const { loading } = useGetSsoIdentityProvidersQuery({
|
||||
fetchPolicy: 'network-only',
|
||||
skip: currentWorkspace?.hasValidEnterpriseKey === false,
|
||||
onCompleted: (data) => {
|
||||
setSSOIdentitiesProviders(
|
||||
data?.listSSOIdentityProvidersByWorkspaceId ?? [],
|
||||
);
|
||||
setSSOIdentitiesProviders(data?.getSSOIdentityProviders ?? []);
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
enqueueSnackBar(error.message, {
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const LIST_WORKSPACE_SSO_IDENTITY_PROVIDERS = gql`
|
||||
query ListSSOIdentityProvidersByWorkspaceId {
|
||||
listSSOIdentityProvidersByWorkspaceId {
|
||||
export const GET_SSO_IDENTITY_PROVIDERS = gql`
|
||||
query GetSSOIdentityProviders {
|
||||
getSSOIdentityProviders {
|
||||
type
|
||||
id
|
||||
name
|
||||
|
||||
@ -0,0 +1,209 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { SSOService } from 'src/engine/core-modules/sso/services/sso.service';
|
||||
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
|
||||
import { WorkspaceSSOIdentityProvider } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { SSOException } from 'src/engine/core-modules/sso/sso.exception';
|
||||
|
||||
describe('SSOService', () => {
|
||||
let service: SSOService;
|
||||
let repository: Repository<WorkspaceSSOIdentityProvider>;
|
||||
let billingService: BillingService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
SSOService,
|
||||
{
|
||||
provide: getRepositoryToken(WorkspaceSSOIdentityProvider, 'core'),
|
||||
useClass: Repository,
|
||||
},
|
||||
{
|
||||
provide: BillingService,
|
||||
useValue: {
|
||||
hasEntitlement: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useValue: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: ExceptionHandlerService,
|
||||
useValue: {
|
||||
captureExceptions: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<SSOService>(SSOService);
|
||||
repository = module.get<Repository<WorkspaceSSOIdentityProvider>>(
|
||||
getRepositoryToken(WorkspaceSSOIdentityProvider, 'core'),
|
||||
);
|
||||
billingService = module.get<BillingService>(BillingService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
describe('createOIDCIdentityProvider', () => {
|
||||
it('should create an OIDC identity provider successfully', async () => {
|
||||
const workspaceId = 'workspace-123';
|
||||
const data = {
|
||||
issuer: 'https://example.com',
|
||||
clientID: 'client-id',
|
||||
clientSecret: 'client-secret',
|
||||
name: 'Test Provider',
|
||||
};
|
||||
const mockIssuer = { metadata: { issuer: 'https://example.com' } };
|
||||
const mockSavedProvider = {
|
||||
id: 'provider-123',
|
||||
type: 'OIDC',
|
||||
name: 'Test Provider',
|
||||
status: 'ACTIVE',
|
||||
issuer: 'https://example.com',
|
||||
};
|
||||
|
||||
jest.spyOn(billingService, 'hasEntitlement').mockResolvedValue(true);
|
||||
jest
|
||||
.spyOn(service as any, 'getIssuerForOIDC')
|
||||
.mockResolvedValue(mockIssuer);
|
||||
jest
|
||||
.spyOn(repository, 'save')
|
||||
.mockResolvedValue(mockSavedProvider as any);
|
||||
|
||||
const result = await service.createOIDCIdentityProvider(
|
||||
data,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'provider-123',
|
||||
type: 'OIDC',
|
||||
name: 'Test Provider',
|
||||
status: 'ACTIVE',
|
||||
issuer: 'https://example.com',
|
||||
});
|
||||
|
||||
expect(billingService.hasEntitlement).toHaveBeenCalledWith(
|
||||
workspaceId,
|
||||
'SSO',
|
||||
);
|
||||
expect(repository.save).toHaveBeenCalledWith({
|
||||
type: 'OIDC',
|
||||
clientID: 'client-id',
|
||||
clientSecret: 'client-secret',
|
||||
issuer: 'https://example.com',
|
||||
name: 'Test Provider',
|
||||
workspaceId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an exception when SSO is disabled', async () => {
|
||||
const workspaceId = 'workspace-123';
|
||||
const data = {
|
||||
issuer: 'https://example.com',
|
||||
clientID: 'client-id',
|
||||
clientSecret: 'client-secret',
|
||||
name: 'Test Provider',
|
||||
};
|
||||
|
||||
jest.spyOn(billingService, 'hasEntitlement').mockResolvedValue(false);
|
||||
|
||||
const result = await service.createOIDCIdentityProvider(
|
||||
data,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
expect(result).toBeInstanceOf(SSOException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteSSOIdentityProvider', () => {
|
||||
it('should delete the identity provider successfully', async () => {
|
||||
const identityProviderId = 'provider-123';
|
||||
const workspaceId = 'workspace-123';
|
||||
const mockProvider = { id: identityProviderId };
|
||||
|
||||
jest.spyOn(repository, 'findOne').mockResolvedValue(mockProvider as any);
|
||||
jest.spyOn(repository, 'delete').mockResolvedValue(null as any);
|
||||
|
||||
const result = await service.deleteSSOIdentityProvider(
|
||||
identityProviderId,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
expect(result).toEqual({ identityProviderId: 'provider-123' });
|
||||
expect(repository.findOne).toHaveBeenCalledWith({
|
||||
where: { id: identityProviderId, workspaceId },
|
||||
});
|
||||
expect(repository.delete).toHaveBeenCalledWith({
|
||||
id: identityProviderId,
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an exception if the identity provider does not exist', async () => {
|
||||
const identityProviderId = 'provider-123';
|
||||
const workspaceId = 'workspace-123';
|
||||
|
||||
jest.spyOn(repository, 'findOne').mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
service.deleteSSOIdentityProvider(identityProviderId, workspaceId),
|
||||
).rejects.toThrow(SSOException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAuthorizationUrlForSSO', () => {
|
||||
it('should return an authorization URL', async () => {
|
||||
const identityProviderId = 'provider-123';
|
||||
const searchParams = { client: 'web' };
|
||||
const mockIdentityProvider = {
|
||||
id: 'provider-123',
|
||||
type: 'OIDC',
|
||||
};
|
||||
|
||||
jest
|
||||
.spyOn(repository, 'findOne')
|
||||
.mockResolvedValue(mockIdentityProvider as any);
|
||||
jest
|
||||
.spyOn(service as any, 'buildIssuerURL')
|
||||
.mockReturnValue('https://example.com/auth');
|
||||
|
||||
const result = await service.getAuthorizationUrlForSSO(
|
||||
identityProviderId,
|
||||
searchParams,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'provider-123',
|
||||
authorizationURL: 'https://example.com/auth',
|
||||
type: 'OIDC',
|
||||
});
|
||||
|
||||
expect(repository.findOne).toHaveBeenCalledWith({
|
||||
where: { id: identityProviderId },
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an exception if the identity provider is not found', async () => {
|
||||
const identityProviderId = 'provider-123';
|
||||
const searchParams = {};
|
||||
|
||||
jest.spyOn(repository, 'findOne').mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
service.getAuthorizationUrlForSSO(identityProviderId, searchParams),
|
||||
).rejects.toThrow(SSOException);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -223,7 +223,7 @@ export class SSOService {
|
||||
};
|
||||
}
|
||||
|
||||
async listSSOIdentityProvidersByWorkspaceId(workspaceId: string) {
|
||||
async getSSOIdentityProviders(workspaceId: string) {
|
||||
return (await this.workspaceSSOIdentityProviderRepository.find({
|
||||
where: { workspaceId },
|
||||
select: ['id', 'name', 'type', 'issuer', 'status'],
|
||||
|
||||
@ -42,12 +42,12 @@ export class SSOResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard)
|
||||
@UseGuards(WorkspaceAuthGuard, EnterpriseFeaturesEnabledGuard)
|
||||
@Query(() => [FindAvailableSSOIDPOutput])
|
||||
async listSSOIdentityProvidersByWorkspaceId(
|
||||
async getSSOIdentityProviders(
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
) {
|
||||
return this.sSOService.listSSOIdentityProvidersByWorkspaceId(workspaceId);
|
||||
return this.sSOService.getSSOIdentityProviders(workspaceId);
|
||||
}
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard, EnterpriseFeaturesEnabledGuard)
|
||||
|
||||
Reference in New Issue
Block a user