Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 6 additions & 3 deletions src/auth/tenant.ts
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export interface TenantServerResponse {
name: string;
type?: TenantServerType;
displayName?: string;
allowPasswordSignup: boolean;
enableEmailLinkSignin: boolean;
allowPasswordSignup?: boolean;
enableEmailLinkSignin?: boolean;
}

/** The interface representing the listTenant API response. */
Expand Down Expand Up @@ -181,7 +181,10 @@ export class Tenant {
try {
this.emailSignInConfig = new EmailSignInConfig(response);
} catch (e) {
this.emailSignInConfig = undefined;
// If allowPasswordSignup is undefined, it is disabled by default.
this.emailSignInConfig = new EmailSignInConfig({
allowPasswordSignup: false,
});
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,6 @@ declare namespace admin.auth {
providerId: string;

/**

* @return A JSON-serializable representation of this object.
*/
toJSON(): Object;
Expand Down Expand Up @@ -5191,4 +5190,4 @@ declare namespace admin.projectManagement {
declare module 'firebase-admin' {
}

export = admin;
export = admin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

157 changes: 155 additions & 2 deletions test/integration/auth.spec.ts
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ import * as scrypt from 'scrypt';
import firebase from '@firebase/app';
import '@firebase/auth';
import {clone} from 'lodash';
import {generateRandomString, projectId, apiKey, noServiceAccountApp} from './setup';
import {
generateRandomString, projectId, apiKey, noServiceAccountApp, cmdArgs,
} from './setup';
import url = require('url');
import * as mocks from '../resources/mocks';
import { AuthProviderConfig } from '../../src/auth/auth-config';
import { deepExtend } from '../../src/utils/deep-copy';
import { deepExtend, deepCopy } from '../../src/utils/deep-copy';

/* tslint:disable:no-var-requires */
const chalk = require('chalk');
/* tslint:enable:no-var-requires */

chai.should();
chai.use(chaiAsPromised);
Expand Down Expand Up @@ -428,6 +434,153 @@ describe('admin.auth', () => {
});
});

describe('Tenant management operations', () => {
// TODO: Add basic user management tests for multi-tenancy when Auth client SDK starts supporting it.
let createdTenantId: string;
const createdTenants: string[] = [];
const tenantOptions: admin.auth.CreateTenantRequest = {
displayName: 'testTenant1',
type: 'lightweight',
emailSignInConfig: {
enabled: true,
passwordRequired: true,
},
};
const expectedCreatedTenant: any = {
displayName: 'testTenant1',
emailSignInConfig: {
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/
// Passing arrow functions (aka "lambdas") to Mocha is discouraged.
// Lambdas lexically bind this and cannot access the Mocha context.
before(function() {
/* tslint:disable:no-console */
if (!cmdArgs.testMultiTenancy) {
// To enable, run: npm run test:integration -- --testMultiTenancy
// By default we skip multi-tenancy as it is a Google Cloud Identity Platform
// feature only and requires to be enabled via the Cloud Console.
console.log(chalk.yellow(' Skipping multi-tenancy tests.'));
this.skip();
}
/* tslint:enable:no-console */
});

// Delete test tenants at the end of test suite.
after(() => {
const promises: Array<Promise<any>> = [];
createdTenants.forEach((tenantId) => {
promises.push(
admin.auth().deleteTenant(tenantId).catch((error) => {/** Ignore. */}));
});
return Promise.all(promises);
});

it('createTenant() should resolve with a new tenant', () => {
return admin.auth().createTenant(tenantOptions)
.then((actualTenant) => {
createdTenantId = actualTenant.tenantId;
createdTenants.push(createdTenantId);
expectedCreatedTenant.tenantId = createdTenantId;
expect(actualTenant.toJSON()).to.deep.equal(expectedCreatedTenant);
});
});

it('getTenant() should resolve with expected tenant', () => {
return admin.auth().getTenant(createdTenantId)
.then((actualTenant) => {
expect(actualTenant.toJSON()).to.deep.equal(expectedCreatedTenant);
});
});

it('updateTenant() should resolve with the updated tenant', () => {
expectedUpdatedTenant.tenantId = createdTenantId;
expectedUpdatedTenant2.tenantId = createdTenantId;
const updatedOptions: admin.auth.UpdateTenantRequest = {
displayName: expectedUpdatedTenant.displayName,
emailSignInConfig: {
enabled: false,
},
};
const updatedOptions2: admin.auth.UpdateTenantRequest = {
emailSignInConfig: {
enabled: true,
passwordRequired: false,
},
};
return admin.auth().updateTenant(createdTenantId, updatedOptions)
.then((actualTenant) => {
expect(actualTenant.toJSON()).to.deep.equal(expectedUpdatedTenant);
return admin.auth().updateTenant(createdTenantId, updatedOptions2);
})
.then((actualTenant) => {
expect(actualTenant.toJSON()).to.deep.equal(expectedUpdatedTenant2);
});
});

it('listTenants() should resolve with expected number of tenants', () => {
const allTenantIds: string[] = [];
const tenantOptions2 = deepCopy(tenantOptions);
tenantOptions2.displayName = 'testTenant2';
const listAllTenantIds = (tenantIds: string[], nextPageToken?: string): Promise<void> => {
return admin.auth().listTenants(100, nextPageToken)
.then((result) => {
result.tenants.forEach((tenant) => {
tenantIds.push(tenant.tenantId);
});
if (result.pageToken) {
return listAllTenantIds(tenantIds, result.pageToken);
}
});
};
return admin.auth().createTenant(tenantOptions2)
.then((actualTenant) => {
createdTenants.push(actualTenant.tenantId);
// Test listTenants returns the expected tenants.
return listAllTenantIds(allTenantIds);
})
.then(() => {
// All created tenants should be in the list of tenants.
createdTenants.forEach((tenantId) => {
expect(allTenantIds).to.contain(tenantId);
});
});
});

it('deleteTenant() should successfully delete the provided tenant', () => {
return admin.auth().deleteTenant(createdTenantId)
.then(() => {
return admin.auth().getTenant(createdTenantId);
})
.then((result) => {
throw new Error('unexpected success');
})
.catch((error) => {
expect(error.code).to.equal('auth/tenant-not-found');
});
});
});

describe('SAML configuration operations', () => {
const authProviderConfig1 = {
providerId: 'saml.' + generateRandomString(5),
Expand Down
15 changes: 15 additions & 0 deletions test/unit/auth/tenant.spec.ts
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,21 @@ describe('Tenant', () => {
expect(() => new Tenant(invalidOptions))
.to.throw('INTERNAL ASSERT FAILED: Invalid tenant response');
});

it('should set default EmailSignInConfig when allowPasswordSignup is undefined', () => {
const serverResponse: TenantServerResponse = {
name: 'projects/project1/tenants/TENANT_ID',
displayName: 'TENANT_DISPLAY_NAME',
};
expect(() => {
const tenantWithoutAllowPasswordSignup = new Tenant(serverResponse);

expect(tenantWithoutAllowPasswordSignup.displayName).to.equal(serverResponse.displayName);
expect(tenantWithoutAllowPasswordSignup.tenantId).to.equal('TENANT_ID');
expect(tenantWithoutAllowPasswordSignup.emailSignInConfig.enabled).to.be.false;
expect(tenantWithoutAllowPasswordSignup.emailSignInConfig.passwordRequired).to.be.true;
}).not.to.throw();
});
});

describe('toJSON()', () => {
Expand Down