Skip to content

Commit 27e5133

Browse files
authored
Merge pull request #19488 from mozilla/FXA-12433
task(auth): Expose more detailed session status info
2 parents 2c68942 + 890fa53 commit 27e5133

4 files changed

Lines changed: 336 additions & 31 deletions

File tree

packages/fxa-auth-server/lib/routes/session.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const { recordSecurityEvent } = require('./utils/security-event');
1919
const { getOptionalCmsEmailConfig } = require('./utils/account');
2020
const { Container } = require('typedi');
2121
const { RelyingPartyConfigurationManager } = require('@fxa/shared/cms');
22+
const authMethods = require('../authMethods');
2223

2324
module.exports = function (
2425
log,
@@ -275,15 +276,56 @@ module.exports = function (
275276
schema: isA.object({
276277
state: isA.string().required(),
277278
uid: isA.string().regex(HEX_STRING).required(),
279+
details: isA.object({
280+
accountEmailVerified: isA.boolean(),
281+
sessionVerificationMethod: isA.string().allow(null),
282+
sessionVerificationSuccessful: isA.boolean(),
283+
sessionVerificationMeetsMinimumAAL: isA.boolean(),
284+
}),
278285
}),
279286
},
280287
},
281288
handler: async function (request) {
282289
log.begin('Session.status', request);
283290
const sessionToken = request.auth.credentials;
291+
const account = await db.account(sessionToken.uid);
292+
293+
// Make sure the account still exists
294+
if (!account) {
295+
throw error.unknownAccount();
296+
}
297+
298+
// Check account assurance level
299+
const accountAmr = await authMethods.availableAuthenticationMethods(
300+
db,
301+
account
302+
);
303+
const accountAal = authMethods.maximumAssuranceLevel(accountAmr);
304+
const sessionAal = sessionToken.authenticatorAssuranceLevel;
305+
306+
// Build response
307+
const accountEmailVerified =
308+
account.emails?.primaryEmail?.isVerified || false;
309+
310+
const sessionVerificationMethod = sessionToken.verificationMethod;
311+
312+
// See verified-session-token auth strategy
313+
const sessionVerificationSuccessful =
314+
sessionToken.tokenVerificationId == null &&
315+
sessionToken.tokenVerified !== false;
316+
317+
// Account Assurance Level
318+
const sessionVerificationMeetsMinimumAAL = sessionAal >= accountAal;
319+
284320
return {
285321
state: sessionToken.state,
286322
uid: sessionToken.uid,
323+
details: {
324+
accountEmailVerified,
325+
sessionVerificationMethod,
326+
sessionVerificationSuccessful,
327+
sessionVerificationMeetsMinimumAAL,
328+
},
287329
};
288330
},
289331
},

packages/fxa-auth-server/test/local/routes/auth-schemes/verified-session-token.js

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ const AppError = require('../../../../lib/error');
88
const {
99
strategy,
1010
} = require('../../../../lib/routes/auth-schemes/verified-session-token');
11-
const authMethods = require('../../../../lib/authMethods');
12-
13-
const HAWK_HEADER = 'Hawk id="123", ts="123", nonce="123", mac="123"';
1411

1512
describe('lib/routes/auth-schemes/verified-session-token', () => {
1613
let config;
@@ -21,10 +18,6 @@ describe('lib/routes/auth-schemes/verified-session-token', () => {
2118
let request;
2219
let getCredentialsFunc;
2320

24-
before(() => {
25-
sinon.stub(authMethods, 'availableAuthenticationMethods');
26-
});
27-
2821
beforeEach(() => {
2922
// Default valid state. This state should pass email verified check, session token verified check,
3023
// and account assurance level check.
@@ -53,12 +46,10 @@ describe('lib/routes/auth-schemes/verified-session-token', () => {
5346
authenticatorAssuranceLevel: 1,
5447
};
5548

56-
authMethods.availableAuthenticationMethods = sinon.fake.resolves(
57-
new Set(['pwd', 'email'])
58-
);
59-
6049
request = {
61-
headers: { authorization: HAWK_HEADER },
50+
headers: {
51+
authorization: 'Hawk id="123", ts="123", nonce="123", mac="123"',
52+
},
6253
auth: { mode: 'required' },
6354
route: { path: '/foo/{id}' },
6455
};
@@ -209,9 +200,10 @@ describe('lib/routes/auth-schemes/verified-session-token', () => {
209200

210201
it('fails when AAL mismatch', async () => {
211202
// Force account AAL=2 by returning otp along with pwd/email
212-
authMethods.availableAuthenticationMethods = sinon.fake.resolves(
213-
new Set(['pwd', 'email', 'otp'])
214-
);
203+
db.totpToken = sinon.fake.resolves({
204+
verified: true,
205+
enabled: true,
206+
});
215207

216208
const authStrategy = strategy(getCredentialsFunc, db, config, statsd)();
217209
try {
@@ -231,9 +223,10 @@ describe('lib/routes/auth-schemes/verified-session-token', () => {
231223

232224
it('skips AAL check when configured', async () => {
233225
// Force account AAL=2 by returning otp along with pwd/email
234-
authMethods.availableAuthenticationMethods = sinon.fake.resolves(
235-
new Set(['pwd', 'email', 'otp'])
236-
);
226+
db.totpToken = sinon.fake.resolves({
227+
enabled: true,
228+
verified: true,
229+
});
237230

238231
// Skip AAL check for path
239232
config.authStrategies.verifiedSessionToken.skipAalCheckForRoutes = '/foo.*';

0 commit comments

Comments
 (0)