Skip to content

Removes all usage of tenant types. #611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions src/auth/tenant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,20 @@ import {
EmailSignInConfig, EmailSignInConfigServerRequest, EmailSignInProviderConfig,
} from './auth-config';

/** The server side tenant type enum. */
export type TenantServerType = 'LIGHTWEIGHT' | 'FULL_SERVICE' | 'TYPE_UNSPECIFIED';

/** The client side tenant type enum. */
export type TenantType = 'lightweight' | 'full_service' | 'type_unspecified';

/** The TenantOptions interface used for create/read/update tenant operations. */
export interface TenantOptions {
displayName?: string;
type?: TenantType;
emailSignInConfig?: EmailSignInProviderConfig;
}

/** The corresponding server side representation of a TenantOptions object. */
export interface TenantOptionsServerRequest extends EmailSignInConfigServerRequest {
displayName?: string;
type?: TenantServerType;
}

/** The tenant server response interface. */
export interface TenantServerResponse {
name: string;
type?: TenantServerType;
displayName?: string;
allowPasswordSignup?: boolean;
enableEmailLinkSignin?: boolean;
Expand All @@ -61,7 +52,6 @@ export interface ListTenantsResult {
*/
export class Tenant {
public readonly tenantId: string;
public readonly type?: TenantType;
public readonly displayName?: string;
public readonly emailSignInConfig?: EmailSignInConfig;

Expand All @@ -82,9 +72,6 @@ export class Tenant {
if (typeof tenantOptions.displayName !== 'undefined') {
request.displayName = tenantOptions.displayName;
}
if (typeof tenantOptions.type !== 'undefined') {
request.type = tenantOptions.type.toUpperCase() as TenantServerType;
}
return request;
}

Expand Down Expand Up @@ -112,7 +99,6 @@ export class Tenant {
private static validate(request: any, createRequest: boolean) {
const validKeys = {
displayName: true,
type: true,
emailSignInConfig: true,
};
const label = createRequest ? 'CreateTenantRequest' : 'UpdateTenantRequest';
Expand All @@ -139,21 +125,6 @@ export class Tenant {
`"${label}.displayName" must be a valid non-empty string.`,
);
}
// Validate type if provided.
if (typeof request.type !== 'undefined' && !createRequest) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'"Tenant.type" is an immutable property.',
);
}
if (createRequest &&
request.type !== 'full_service' &&
request.type !== 'lightweight') {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`"${label}.type" must be either "full_service" or "lightweight".`,
);
}
// Validate emailSignInConfig type if provided.
if (typeof request.emailSignInConfig !== 'undefined') {
// This will throw an error if invalid.
Expand All @@ -177,7 +148,6 @@ export class Tenant {
}
this.tenantId = tenantId;
this.displayName = response.displayName;
this.type = (response.type && response.type.toLowerCase()) || undefined;
try {
this.emailSignInConfig = new EmailSignInConfig(response);
} catch (e) {
Expand All @@ -193,7 +163,6 @@ export class Tenant {
return {
tenantId: this.tenantId,
displayName: this.displayName,
type: this.type,
emailSignInConfig: this.emailSignInConfig && this.emailSignInConfig.toJSON(),
};
}
Expand Down
28 changes: 2 additions & 26 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1064,8 +1064,6 @@ declare namespace admin.auth {
dynamicLinkDomain?: string;
}

type TenantType = 'lightweight' | 'full_service';

/**
* Interface representing a tenant configuration.
*
Expand All @@ -1076,8 +1074,8 @@ declare namespace admin.auth {
* Before multi-tenancy can be used on a Google Cloud Identity Platform project,
* tenants must be allowed on that project via the Cloud Console UI.
*
* A tenant configuration provides information such as the type of tenant (lightweight or
* full service), display name, tenant identifier and email authentication configuration.
* A tenant configuration provides information such as the display name, tenant
* identifier and email authentication configuration.
* For OIDC/SAML provider configuration management, `TenantAwareAuth` instances should
* be used instead of a `Tenant` to retrieve the list of configured IdPs on a tenant.
* When configuring these providers, note that tenants will inherit
Expand All @@ -1093,18 +1091,6 @@ declare namespace admin.auth {
*/
tenantId: string;

/**
* The tenant type: `lightweight` or `full_service`.
* Tenants that use separate billing and quota will require their own project and
* must be defined as `full_service`.
* `full_service` tenants may be subject to quota creation limits.
* For additional project quota increases, refer to
* [project quota requests](https://support.google.com/cloud/answer/6330231?hl=en).
* In addition, deleted `full_service` tenants may take 30 days after deletion
* before they are completely removed.
*/
type?: admin.auth.TenantType;

/**
* The tenant display name.
*/
Expand Down Expand Up @@ -1165,11 +1151,6 @@ declare namespace admin.auth {
* Interface representing the properties to set on a new tenant.
*/
interface CreateTenantRequest extends UpdateTenantRequest {

/**
* The newly created tenant type. This can be `lightweight` or `full_service`.
*/
type: admin.auth.TenantType;
}

/**
Expand Down Expand Up @@ -2016,11 +1997,6 @@ declare namespace admin.auth {

/**
* Updates an existing tenant configuration.
*
* Tenant types cannot be modified after creation.
* If a tenant type needs to be changed after creation, a new tenant with the expected
* type needs to be created and the users/configurations of existing tenant copied to the
* new tenant.
*
* @param tenantId The `tenantId` corresponding to the tenant to delete.
* @param tenantOptions The properties to update on the provided tenant.
Expand Down
6 changes: 1 addition & 5 deletions test/integration/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,6 @@ describe('admin.auth', () => {
const createdTenants: string[] = [];
const tenantOptions: admin.auth.CreateTenantRequest = {
displayName: 'testTenant1',
type: 'lightweight',
emailSignInConfig: {
enabled: true,
passwordRequired: true,
Expand All @@ -451,23 +450,20 @@ describe('admin.auth', () => {
enabled: true,
passwordRequired: true,
},
type: 'lightweight',
};
const expectedUpdatedTenant: any = {
displayName: 'testTenantUpdated',
emailSignInConfig: {
enabled: false,
passwordRequired: true,
},
type: 'lightweight',
};
const expectedUpdatedTenant2: any = {
displayName: 'testTenantUpdated',
emailSignInConfig: {
enabled: true,
passwordRequired: false,
},
type: 'lightweight',
};

// https://mochajs.org/
Expand Down Expand Up @@ -574,7 +570,7 @@ describe('admin.auth', () => {
});
});

// Ignore email action link tests for now as there is a bug for lightweight tenants:
// Ignore email action link tests for now as there is a bug in the returned tenant ID:
// expected '1085102361755-testTenant1-6rjsn' to equal 'testTenant1-6rjsn'
xit('generateEmailVerificationLink() should generate the link for tenant specific user', () => {
// Generate email verification link to confirm it is generated in the expected
Expand Down
37 changes: 0 additions & 37 deletions test/unit/auth/auth-api-request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3783,15 +3783,13 @@ AUTH_REQUEST_HANDLER_TESTS.forEach((handler) => {
const tenantId = 'tenant_id';
const tenantOptions: TenantOptions = {
displayName: 'TENANT_DISPLAY_NAME',
type: 'lightweight',
emailSignInConfig: {
enabled: true,
passwordRequired: true,
},
};
const expectedRequest = {
displayName: 'TENANT_DISPLAY_NAME',
type: 'LIGHTWEIGHT',
allowPasswordSignup: true,
enableEmailLinkSignin: false,
};
Expand All @@ -3811,24 +3809,6 @@ AUTH_REQUEST_HANDLER_TESTS.forEach((handler) => {
});
});

it('should be rejected given valid parameters with no type', () => {
const expectedError = new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'"CreateTenantRequest.type" must be either "full_service" or "lightweight".',
);
// Initialize CreateTenantRequest with missing type.
const invalidOptions = deepCopy(tenantOptions);
delete invalidOptions.type;

const requestHandler = handler.init(mockApp) as AuthRequestHandler;
return requestHandler.createTenant(invalidOptions)
.then((result) => {
throw new Error('Unexpected success');
}, (error) => {
expect(error).to.deep.equal(expectedError);
});
});

it('should be rejected given invalid parameters', () => {
const expectedError = new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
Expand Down Expand Up @@ -4015,23 +3995,6 @@ AUTH_REQUEST_HANDLER_TESTS.forEach((handler) => {
});
});

it('should be rejected given an unmodifiable property', () => {
const expectedError = new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'"Tenant.type" is an immutable property.',
);
const invalidOptions = deepCopy(tenantOptions);
(invalidOptions as TenantOptions).type = 'full_service';

const requestHandler = handler.init(mockApp) as AuthRequestHandler;
return requestHandler.updateTenant(tenantId, invalidOptions)
.then((result) => {
throw new Error('Unexpected success');
}, (error) => {
expect(error).to.deep.equal(expectedError);
});
});

it('should be rejected when the backend returns a response missing name', () => {
const expectedPath = path + '?updateMask=allowPasswordSignup,enableEmailLinkSignin,displayName';
const expectedError = new FirebaseAuthError(
Expand Down
8 changes: 2 additions & 6 deletions test/unit/auth/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3058,7 +3058,6 @@ AUTH_CONFIGS.forEach((testConfig) => {
const tenantId = 'tenant_id';
const serverResponse: TenantServerResponse = {
name: 'projects/project_id/tenants/tenant_id',
type: 'FULL_SERVICE',
displayName: 'TENANT_DISPLAY_NAME',
allowPasswordSignup: true,
enableEmailLinkSignin: false,
Expand Down Expand Up @@ -3343,7 +3342,6 @@ AUTH_CONFIGS.forEach((testConfig) => {
const tenantId = 'tenant_id';
const tenantOptions: TenantOptions = {
displayName: 'TENANT_DISPLAY_NAME',
type: 'lightweight',
emailSignInConfig: {
enabled: true,
passwordRequired: true,
Expand All @@ -3354,7 +3352,6 @@ AUTH_CONFIGS.forEach((testConfig) => {
displayName: 'TENANT_DISPLAY_NAME',
allowPasswordSignup: true,
enableEmailLinkSignin: false,
type: 'LIGHTWEIGHT',
};
const expectedTenant = new Tenant(serverResponse);
const expectedError = new FirebaseAuthError(
Expand Down Expand Up @@ -3450,7 +3447,6 @@ AUTH_CONFIGS.forEach((testConfig) => {
};
const serverResponse: TenantServerResponse = {
name: 'projects/project_id/tenants/tenant_id',
type: 'FULL_SERVICE',
displayName: 'TENANT_DISPLAY_NAME',
allowPasswordSignup: true,
enableEmailLinkSignin: false,
Expand Down Expand Up @@ -3498,9 +3494,9 @@ AUTH_CONFIGS.forEach((testConfig) => {
});

it('should be rejected given TenantOptions with invalid update property', () => {
// Updating the type of an existing tenant will throw an error as type is
// Updating the tenantId of an existing tenant will throw an error as tenantId is
// an immutable property.
return (auth as Auth).updateTenant(tenantId, {type: 'lightweight'})
return (auth as Auth).updateTenant(tenantId, {tenantId: 'unmodifiable'} as any)
.then(() => {
throw new Error('Unexpected success');
})
Expand Down
36 changes: 0 additions & 36 deletions test/unit/auth/tenant.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,6 @@ describe('Tenant', () => {
}).to.throw('"EmailSignInConfig.enabled" must be a boolean.');
});

it('should throw when type is specified in an update request', () => {
const tenantOptionsClientRequest: TenantOptions = deepCopy(tenantOptions);
tenantOptionsClientRequest.type = 'lightweight';
expect(() => Tenant.buildServerRequest(tenantOptionsClientRequest, !createRequest))
.to.throw('"Tenant.type" is an immutable property.');
});

it('should not throw on valid client request object', () => {
const tenantOptionsClientRequest = deepCopy(clientRequest);
expect(() => {
Expand Down Expand Up @@ -129,29 +122,16 @@ describe('Tenant', () => {
describe('for a create request', () => {
it('should return the expected server request', () => {
const tenantOptionsClientRequest: TenantOptions = deepCopy(clientRequest);
tenantOptionsClientRequest.type = 'lightweight';
const tenantOptionsServerRequest: TenantServerResponse = deepCopy(serverRequest);
delete tenantOptionsServerRequest.name;
tenantOptionsServerRequest.type = 'LIGHTWEIGHT';

expect(Tenant.buildServerRequest(tenantOptionsClientRequest, createRequest))
.to.deep.equal(tenantOptionsServerRequest);
});

const invalidTypes = [undefined, 'invalid', null, NaN, 0, 1, true, false, '', [], [1, 'a'], {}, { a: 1 }, _.noop];
invalidTypes.forEach((invalidType) => {
it('should throw on invalid type ' + JSON.stringify(invalidType), () => {
const tenantOptionsClientRequest: TenantOptions = deepCopy(tenantOptions);
tenantOptionsClientRequest.type = invalidType as any;
expect(() => Tenant.buildServerRequest(tenantOptionsClientRequest, createRequest))
.to.throw(`"CreateTenantRequest.type" must be either "full_service" or "lightweight".`);
});
});

it('should throw on invalid EmailSignInConfig', () => {
const tenantOptionsClientRequest: TenantOptions = deepCopy(clientRequest);
tenantOptionsClientRequest.emailSignInConfig = null;
tenantOptionsClientRequest.type = 'full_service';

expect(() => Tenant.buildServerRequest(tenantOptionsClientRequest, createRequest))
.to.throw('"EmailSignInConfig" must be a non-null object.');
Expand Down Expand Up @@ -184,15 +164,6 @@ describe('Tenant', () => {
}).to.throw('"CreateTenantRequest.displayName" must be a valid non-empty string.');
});
});

invalidTypes.forEach((invalidType) => {
it('should throw on creation with invalid type ' + JSON.stringify(invalidType), () => {
const tenantOptionsClientRequest: TenantOptions = deepCopy(tenantOptions);
tenantOptionsClientRequest.type = invalidType as any;
expect(() => Tenant.buildServerRequest(tenantOptionsClientRequest, createRequest))
.to.throw(`"CreateTenantRequest.type" must be either "full_service" or "lightweight".`);
});
});
});
});

Expand All @@ -214,7 +185,6 @@ describe('Tenant', () => {

describe('constructor', () => {
const serverRequestCopy: TenantServerResponse = deepCopy(serverRequest);
serverRequestCopy.type = 'LIGHTWEIGHT';
const tenant = new Tenant(serverRequestCopy);
it('should not throw on valid initialization', () => {
expect(() => new Tenant(serverRequest)).not.to.throw();
Expand All @@ -228,10 +198,6 @@ describe('Tenant', () => {
expect(tenant.displayName).to.equal('TENANT_DISPLAY_NAME');
});

it('should set readonly property type', () => {
expect(tenant.type).to.equal('lightweight');
});

it('should set readonly property emailSignInConfig', () => {
const expectedEmailSignInConfig = new EmailSignInConfig({
allowPasswordSignup: true,
Expand Down Expand Up @@ -266,11 +232,9 @@ describe('Tenant', () => {

describe('toJSON()', () => {
const serverRequestCopy: TenantServerResponse = deepCopy(serverRequest);
serverRequestCopy.type = 'LIGHTWEIGHT';
it('should return the expected object representation of a tenant', () => {
expect(new Tenant(serverRequestCopy).toJSON()).to.deep.equal({
tenantId: 'TENANT_ID',
type: 'lightweight',
displayName: 'TENANT_DISPLAY_NAME',
emailSignInConfig: {
enabled: true,
Expand Down