Enforce system wide sso providers (#9058)
We have recently introduced the possibility to specify workspace specific auth providers. I'm: - introducing system wide auth providers (provided by clientConfig) - making sure workspace specific auth providers belong to system wide auth providers set
This commit is contained in:
@ -6,9 +6,10 @@ import { Repository } from 'typeorm';
|
||||
import { AuthException } from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||
import { RefreshTokenService } from 'src/engine/core-modules/auth/token/services/refresh-token.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
|
||||
import { SwitchWorkspaceService } from './switch-workspace.service';
|
||||
|
||||
@ -50,6 +51,12 @@ describe('SwitchWorkspaceService', () => {
|
||||
saveDefaultWorkspaceIfUserHasAccessOrThrow: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: EnvironmentService,
|
||||
useValue: {
|
||||
get: jest.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@ -7,13 +7,15 @@ import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { AuthTokens } from 'src/engine/core-modules/auth/dto/token.entity';
|
||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||
import { RefreshTokenService } from 'src/engine/core-modules/auth/token/services/refresh-token.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthTokens } from 'src/engine/core-modules/auth/dto/token.entity';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
import { getAuthProvidersByWorkspace } from 'src/engine/core-modules/workspace/utils/getAuthProvidersByWorkspace';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { AuthProviders } from 'src/engine/core-modules/workspace/dtos/public-workspace-data.output';
|
||||
import { getAuthProvidersByWorkspace } from 'src/engine/core-modules/workspace/utils/get-auth-providers-by-workspace.util';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SwitchWorkspaceService {
|
||||
@ -25,6 +27,7 @@ export class SwitchWorkspaceService {
|
||||
private readonly userService: UserService,
|
||||
private readonly accessTokenService: AccessTokenService,
|
||||
private readonly refreshTokenService: RefreshTokenService,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
async switchWorkspace(user: User, workspaceId: string) {
|
||||
@ -65,12 +68,23 @@ export class SwitchWorkspaceService {
|
||||
defaultWorkspace: workspace,
|
||||
});
|
||||
|
||||
const systemEnabledProviders: AuthProviders = {
|
||||
google: this.environmentService.get('AUTH_GOOGLE_ENABLED'),
|
||||
magicLink: false,
|
||||
password: this.environmentService.get('AUTH_PASSWORD_ENABLED'),
|
||||
microsoft: this.environmentService.get('AUTH_MICROSOFT_ENABLED'),
|
||||
sso: [],
|
||||
};
|
||||
|
||||
return {
|
||||
id: workspace.id,
|
||||
subdomain: workspace.subdomain,
|
||||
logo: workspace.logo,
|
||||
displayName: workspace.displayName,
|
||||
authProviders: getAuthProvidersByWorkspace(workspace),
|
||||
authProviders: getAuthProvidersByWorkspace({
|
||||
workspace,
|
||||
systemEnabledProviders,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { CaptchaDriverType } from 'src/engine/core-modules/captcha/interfaces';
|
||||
import { AuthProviders } from 'src/engine/core-modules/workspace/dtos/public-workspace-data.output';
|
||||
|
||||
@ObjectType()
|
||||
class Billing {
|
||||
@ -52,6 +53,9 @@ class ApiConfig {
|
||||
|
||||
@ObjectType()
|
||||
export class ClientConfig {
|
||||
@Field(() => AuthProviders, { nullable: false })
|
||||
authProviders: AuthProviders;
|
||||
|
||||
@Field(() => Billing, { nullable: false })
|
||||
billing: Billing;
|
||||
|
||||
|
||||
@ -22,6 +22,13 @@ export class ClientConfigResolver {
|
||||
'BILLING_FREE_TRIAL_DURATION_IN_DAYS',
|
||||
),
|
||||
},
|
||||
authProviders: {
|
||||
google: this.environmentService.get('AUTH_GOOGLE_ENABLED'),
|
||||
magicLink: false,
|
||||
password: this.environmentService.get('AUTH_PASSWORD_ENABLED'),
|
||||
microsoft: this.environmentService.get('AUTH_MICROSOFT_ENABLED'),
|
||||
sso: [],
|
||||
},
|
||||
isSSOEnabled: this.environmentService.get('AUTH_SSO_ENABLED'),
|
||||
signInPrefilled: this.environmentService.get('SIGN_IN_PREFILLED'),
|
||||
isMultiWorkspaceEnabled: this.environmentService.get(
|
||||
|
||||
@ -23,19 +23,24 @@ export class DomainManagerService {
|
||||
|
||||
getFrontUrl() {
|
||||
let baseUrl: URL;
|
||||
const frontPort = this.environmentService.get('FRONT_PORT');
|
||||
const frontDomain = this.environmentService.get('FRONT_DOMAIN');
|
||||
const frontProtocol = this.environmentService.get('FRONT_PROTOCOL');
|
||||
|
||||
if (!this.environmentService.get('FRONT_DOMAIN')) {
|
||||
baseUrl = new URL(this.environmentService.get('SERVER_URL'));
|
||||
const serverUrl = this.environmentService.get('SERVER_URL');
|
||||
|
||||
if (!frontDomain) {
|
||||
baseUrl = new URL(serverUrl);
|
||||
} else {
|
||||
baseUrl = new URL(
|
||||
`${this.environmentService.get('FRONT_PROTOCOL')}://${this.environmentService.get('FRONT_DOMAIN')}`,
|
||||
);
|
||||
baseUrl = new URL(`${frontProtocol}://${frontDomain}`);
|
||||
}
|
||||
|
||||
const port = this.environmentService.get('FRONT_PORT');
|
||||
if (frontPort) {
|
||||
baseUrl.port = frontPort.toString();
|
||||
}
|
||||
|
||||
if (port) {
|
||||
baseUrl.port = port.toString();
|
||||
}
|
||||
if (frontProtocol) {
|
||||
baseUrl.protocol = frontProtocol;
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { getAuthProvidersByWorkspace } from 'src/engine/core-modules/workspace/utils/get-auth-providers-by-workspace.util';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
import { getAuthProvidersByWorkspace } from './getAuthProvidersByWorkspace';
|
||||
|
||||
describe('getAuthProvidersByWorkspace', () => {
|
||||
const mockWorkspace = {
|
||||
isGoogleAuthEnabled: true,
|
||||
@ -20,7 +19,14 @@ describe('getAuthProvidersByWorkspace', () => {
|
||||
|
||||
it('should return correct auth providers for given workspace', () => {
|
||||
const result = getAuthProvidersByWorkspace({
|
||||
...mockWorkspace,
|
||||
workspace: mockWorkspace,
|
||||
systemEnabledProviders: {
|
||||
google: true,
|
||||
magicLink: false,
|
||||
password: true,
|
||||
microsoft: true,
|
||||
sso: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@ -42,8 +48,14 @@ describe('getAuthProvidersByWorkspace', () => {
|
||||
|
||||
it('should handle workspace with no SSO providers', () => {
|
||||
const result = getAuthProvidersByWorkspace({
|
||||
...mockWorkspace,
|
||||
workspaceSSOIdentityProviders: [],
|
||||
workspace: { ...mockWorkspace, workspaceSSOIdentityProviders: [] },
|
||||
systemEnabledProviders: {
|
||||
google: true,
|
||||
magicLink: false,
|
||||
password: true,
|
||||
microsoft: true,
|
||||
sso: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@ -57,8 +69,14 @@ describe('getAuthProvidersByWorkspace', () => {
|
||||
|
||||
it('should disable Microsoft auth if isMicrosoftAuthEnabled is false', () => {
|
||||
const result = getAuthProvidersByWorkspace({
|
||||
...mockWorkspace,
|
||||
isMicrosoftAuthEnabled: false,
|
||||
workspace: { ...mockWorkspace, isMicrosoftAuthEnabled: false },
|
||||
systemEnabledProviders: {
|
||||
google: true,
|
||||
magicLink: false,
|
||||
password: true,
|
||||
microsoft: true,
|
||||
sso: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
@ -3,13 +3,12 @@ import {
|
||||
InternalServerError,
|
||||
NotFoundError,
|
||||
} from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
|
||||
import { workspaceGraphqlApiExceptionHandler } from 'src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util';
|
||||
import {
|
||||
WorkspaceException,
|
||||
WorkspaceExceptionCode,
|
||||
} from 'src/engine/core-modules/workspace/workspace.exception';
|
||||
|
||||
import { workspaceGraphqlApiExceptionHandler } from './workspaceGraphqlApiExceptionHandler';
|
||||
|
||||
describe('workspaceGraphqlApiExceptionHandler', () => {
|
||||
it('should throw NotFoundError when WorkspaceExceptionCode is SUBDOMAIN_NOT_FOUND', () => {
|
||||
const error = new WorkspaceException(
|
||||
@ -0,0 +1,32 @@
|
||||
import { AuthProviders } from 'src/engine/core-modules/workspace/dtos/public-workspace-data.output';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
export const getAuthProvidersByWorkspace = ({
|
||||
workspace,
|
||||
systemEnabledProviders,
|
||||
}: {
|
||||
workspace: Pick<
|
||||
Workspace,
|
||||
| 'isGoogleAuthEnabled'
|
||||
| 'isPasswordAuthEnabled'
|
||||
| 'isMicrosoftAuthEnabled'
|
||||
| 'workspaceSSOIdentityProviders'
|
||||
>;
|
||||
systemEnabledProviders: AuthProviders;
|
||||
}) => {
|
||||
return {
|
||||
google: workspace.isGoogleAuthEnabled && systemEnabledProviders.google,
|
||||
magicLink: false,
|
||||
password:
|
||||
workspace.isPasswordAuthEnabled && systemEnabledProviders.password,
|
||||
microsoft:
|
||||
workspace.isMicrosoftAuthEnabled && systemEnabledProviders.microsoft,
|
||||
sso: workspace.workspaceSSOIdentityProviders.map((identityProvider) => ({
|
||||
id: identityProvider.id,
|
||||
name: identityProvider.name,
|
||||
type: identityProvider.type,
|
||||
status: identityProvider.status,
|
||||
issuer: identityProvider.issuer,
|
||||
})),
|
||||
};
|
||||
};
|
||||
@ -1,17 +0,0 @@
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
export const getAuthProvidersByWorkspace = (workspace: Workspace) => {
|
||||
return {
|
||||
google: workspace.isGoogleAuthEnabled,
|
||||
magicLink: false,
|
||||
password: workspace.isPasswordAuthEnabled,
|
||||
microsoft: workspace.isMicrosoftAuthEnabled,
|
||||
sso: workspace.workspaceSSOIdentityProviders.map((identityProvider) => ({
|
||||
id: identityProvider.id,
|
||||
name: identityProvider.name,
|
||||
type: identityProvider.type,
|
||||
status: identityProvider.status,
|
||||
issuer: identityProvider.issuer,
|
||||
})),
|
||||
};
|
||||
};
|
||||
@ -23,10 +23,13 @@ import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/use
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { ActivateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-input';
|
||||
import { ActivateWorkspaceOutput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-output';
|
||||
import { PublicWorkspaceDataOutput } from 'src/engine/core-modules/workspace/dtos/public-workspace-data.output';
|
||||
import {
|
||||
AuthProviders,
|
||||
PublicWorkspaceDataOutput,
|
||||
} from 'src/engine/core-modules/workspace/dtos/public-workspace-data.output';
|
||||
import { UpdateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/update-workspace-input';
|
||||
import { getAuthProvidersByWorkspace } from 'src/engine/core-modules/workspace/utils/getAuthProvidersByWorkspace';
|
||||
import { workspaceGraphqlApiExceptionHandler } from 'src/engine/core-modules/workspace/utils/workspaceGraphqlApiExceptionHandler';
|
||||
import { getAuthProvidersByWorkspace } from 'src/engine/core-modules/workspace/utils/get-auth-providers-by-workspace.util';
|
||||
import { workspaceGraphqlApiExceptionHandler } from 'src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util';
|
||||
import {
|
||||
WorkspaceException,
|
||||
WorkspaceExceptionCode,
|
||||
@ -207,12 +210,23 @@ export class WorkspaceResolver {
|
||||
}
|
||||
}
|
||||
|
||||
const systemEnabledProviders: AuthProviders = {
|
||||
google: this.environmentService.get('AUTH_GOOGLE_ENABLED'),
|
||||
magicLink: false,
|
||||
password: this.environmentService.get('AUTH_PASSWORD_ENABLED'),
|
||||
microsoft: this.environmentService.get('AUTH_MICROSOFT_ENABLED'),
|
||||
sso: [],
|
||||
};
|
||||
|
||||
return {
|
||||
id: workspace.id,
|
||||
logo: workspaceLogoWithToken,
|
||||
displayName: workspace.displayName,
|
||||
subdomain: workspace.subdomain,
|
||||
authProviders: getAuthProvidersByWorkspace(workspace),
|
||||
authProviders: getAuthProvidersByWorkspace({
|
||||
workspace,
|
||||
systemEnabledProviders,
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user