From 88e47054fd5d534c334f151d4e7a73bc9d6e586f Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 15 Dec 2021 14:57:43 +1000 Subject: [PATCH] WIP SSO tests --- spec/common/services/auth.service.spec.ts | 126 +++++++++++++++------- 1 file changed, 89 insertions(+), 37 deletions(-) diff --git a/spec/common/services/auth.service.spec.ts b/spec/common/services/auth.service.spec.ts index 85cc2b05..aa7b9c73 100644 --- a/spec/common/services/auth.service.spec.ts +++ b/spec/common/services/auth.service.spec.ts @@ -55,12 +55,18 @@ describe('Cipher Service', () => { const kdf = 0; const kdfIterations = 10000; const userId = Utils.newGuid(); + const decodedToken = { sub: userId, email: email, premium: false, }; + const ssoCode = 'SSO_CODE'; + const ssoCodeVerifier = 'SSO_CODE_VERIFIER'; + const ssoRedirectUrl = 'SSO_REDIRECT_URL'; + const ssoOrgId = 'SSO_ORG_ID'; + let authService: AuthService; beforeEach(() => { @@ -139,6 +145,16 @@ describe('Cipher Service', () => { return tokenResponse; } + function newAuthResponse() { + const expected = new AuthResult(); + expected.forcePasswordReset = false; + expected.resetMasterPassword = false; + expected.twoFactor = false; + expected.twoFactorProviders = null; + expected.captchaSiteKey = undefined; + return expected; + } + it('logIn: works in the most simple case (no 2FA, no captcha, no password reset, no KC)', async () => { logInSetup(); commonSetup(); @@ -147,12 +163,7 @@ describe('Cipher Service', () => { tokenService.getTwoFactorToken(email).resolves(null); apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); - const expected = new AuthResult(); - expected.forcePasswordReset = false; - expected.resetMasterPassword = false; - expected.twoFactor = false; - expected.twoFactorProviders = null; - expected.captchaSiteKey = undefined; + const expected = newAuthResponse(); // Act const result = await authService.logIn(email, masterPassword); @@ -232,22 +243,6 @@ describe('Cipher Service', () => { cryptoService.didNotReceive().setEncPrivateKey(Arg.any()); }); - // TODO: this should be logInSso - it('logIn: gets and sets KeyConnector key for enrolled user', async () => { - logInSetup(); - commonSetup(); - const tokenResponse = newTokenResponse(); - tokenResponse.keyConnectorUrl = keyConnectorUrl; - - tokenService.getTwoFactorToken(email).resolves(null); - apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); - - const result = await authService.logIn(email, masterPassword); - - commonSuccessAssertions(); - keyConnectorService.received(1).getAndSetKey(keyConnectorUrl); - }); - it('logIn: makes new KeyPair for an old account', async () => { logInSetup(); commonSetup(); @@ -289,23 +284,80 @@ describe('Cipher Service', () => { expect(result).toEqual(expected); }); - // it('login: new SSO user with Key Connector posts key to the server', async () => { - // logInSetup(); - // commonSetup(); + // SSO - // const tokenResponse = newTokenResponse(); - // tokenResponse.keyConnectorUrl = keyConnectorUrl; - // tokenResponse.key = null; + it('logInSso: basic happy path', async () => { + // TODO: get working when SSO works again + return; + commonSetup(); + const tokenResponse = newTokenResponse(); - // tokenService.getTwoFactorToken(email).resolves(null); - // apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); + tokenService.getTwoFactorToken(null).resolves(null); + apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); - // // const result = await authService.logInSso(); + const result = await authService.logInSso(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId); - // commonSuccessAssertions(); - // cryptoService.received(1).setKey(preloginKey); - // cryptoService.received(1).setEncKey(Arg.any()); - // apiService.received(1).postUserKeyToKeyConnector(keyConnectorUrl, Arg.any()); - // apiService.received(1).postSetKeyConnectorKey(Arg.any()); - // }); + // Assert + // Api call: + apiService.received(1).postIdentityToken(Arg.is(actual => + actual.code === ssoCode && + actual.codeVerifier === ssoCodeVerifier && + actual.redirectUri === ssoRedirectUrl && + actual.device.identifier === deviceId && + actual.provider == null && + actual.token == null && + actual.captchaResponse == null)); + + // Sets local environment: + // TODO: analyse actual behaviour and update + commonSuccessAssertions(); + cryptoService.received(1).setKey(preloginKey); + cryptoService.received(1).setKeyHash(localHashedPassword); + cryptoService.received(1).setEncKey(encKey); + cryptoService.received(1).setEncPrivateKey(privateKey); + + // Negative tests + apiService.didNotReceive().postAccountKeys(Arg.any()); // Did not generate new private key pair + keyConnectorService.didNotReceive().getAndSetKey(Arg.any()); // Did not fetch Key Connector key + apiService.didNotReceive().postUserKeyToKeyConnector(Arg.any(), Arg.any()); // Did not send key to KC + tokenService.didNotReceive().setTwoFactorToken(Arg.any(), Arg.any()); // Did not save 2FA token + + // Return result: + const expected = newAuthResponse(); + expect(result).toEqual(expected); + }); + + it('logInSso: gets and sets KeyConnector key for enrolled user', async () => { + commonSetup(); + const tokenResponse = newTokenResponse(); + tokenResponse.keyConnectorUrl = keyConnectorUrl; + + apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); + + const result = await authService.logInSso(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId); + + commonSuccessAssertions(); + keyConnectorService.received(1).getAndSetKey(keyConnectorUrl); + }); + + it('logInSso: new SSO user with Key Connector posts key to the server', async () => { + // TODO: get working when SSO works again + return; + commonSetup(); + + const tokenResponse = newTokenResponse(); + tokenResponse.keyConnectorUrl = keyConnectorUrl; + tokenResponse.key = null; + + cryptoService.makeKey(Arg.any(), email, kdf, kdfIterations).resolves(preloginKey); + apiService.postIdentityToken(Arg.any()).resolves(tokenResponse); + + const result = await authService.logInSso(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId); + + commonSuccessAssertions(); + cryptoService.received(1).setKey(preloginKey); + cryptoService.received(1).setEncKey(Arg.any()); + apiService.received(1).postUserKeyToKeyConnector(keyConnectorUrl, Arg.any()); + apiService.received(1).postSetKeyConnectorKey(Arg.any()); + }); });