Skip to content

Commit 3372d03

Browse files
authored
Merge pull request #19493 from mozilla/FXA-12136
feat(auth): Add security events for login confirmation skip
2 parents 5179132 + 3bad4f4 commit 3372d03

6 files changed

Lines changed: 65 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CALL assertPatchLevel('176');
2+
3+
INSERT INTO securityEventNames(name) VALUES ('account.signin_confirm_bypass_known_ip'), ('account.signin_confirm_bypass_new_account');
4+
5+
UPDATE dbMetadata SET value = '177' WHERE name = 'schema-patch-level';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- SET NAMES utf8mb4 COLLATE utf8mb4_bin;
2+
--
3+
-- DELETE FROM securityEventNames WHERE name = 'account.signin_confirm_bypass_known_ip';
4+
-- DELETE FROM securityEventNames WHERE name = 'account.signin_confirm_bypass_new_account';
5+
--
6+
-- UPDATE dbMetadata SET value = '176' WHERE name = 'schema-patch-level';
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"level": 176
2+
"level": 177
33
}

packages/fxa-auth-server/lib/routes/account.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,11 @@ export class AccountHandler {
10901090
this.log.info('Account.ipprofiling.seenAddress', {
10911091
uid: account.uid,
10921092
});
1093+
recordSecurityEvent('account.signin_confirm_bypass_known_ip', {
1094+
db: this.db,
1095+
request,
1096+
account,
1097+
});
10931098
return true;
10941099
}
10951100

@@ -1106,6 +1111,11 @@ export class AccountHandler {
11061111
this.log.info('account.signin.confirm.bypass.age', {
11071112
uid: account.uid,
11081113
});
1114+
recordSecurityEvent('account.signin_confirm_bypass_new_account', {
1115+
db: this.db,
1116+
request,
1117+
account,
1118+
});
11091119
return true;
11101120
}
11111121
}

packages/fxa-auth-server/test/local/routes/account.js

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ const makeRoutes = function (options = {}, requireMocks = {}) {
9999
Container.set(AuthLogger, log);
100100

101101
Container.set(AppConfig, config);
102-
Container.set(AccountEventsManager, new AccountEventsManager());
102+
Container.set(
103+
AccountEventsManager,
104+
options.mockAccountEventsManager || new AccountEventsManager()
105+
);
103106
Container.set(RelyingPartyConfigurationManager, rpConfigManager);
104107

105108
const mailer = options.mailer || {};
@@ -3153,7 +3156,7 @@ describe('/account/login', () => {
31533156
});
31543157

31553158
describe('skip for new accounts', () => {
3156-
function setup(enabled, accountCreatedSince) {
3159+
function setup(enabled, accountCreatedSince, makeRoutesOptions = {}) {
31573160
config.signinConfirmation.skipForNewAccounts = {
31583161
enabled: enabled,
31593162
maxAge: 5,
@@ -3184,6 +3187,7 @@ describe('/account/login', () => {
31843187
};
31853188

31863189
const accountRoutes = makeRoutes({
3190+
...makeRoutesOptions,
31873191
checkPassword: function () {
31883192
return Promise.resolve(true);
31893193
},
@@ -3373,14 +3377,30 @@ describe('/account/login', () => {
33733377
it('logs metrics when accountAge is under maxAge config threshold', () => {
33743378
glean.loginConfirmSkipFor.newAccount.reset();
33753379

3376-
setup(true, 0);
3380+
const mockAccountEventsManager = {
3381+
recordSecurityEvent: sinon.fake(),
3382+
};
3383+
setup(true, 0, { mockAccountEventsManager });
33773384

33783385
return runTest(route, mockRequest, () => {
33793386
sinon.assert.calledOnce(glean.loginConfirmSkipFor.newAccount);
33803387
sinon.assert.calledWith(
33813388
statsd.increment,
33823389
'account.signin.confirm.bypass.newAccount'
33833390
);
3391+
sinon.assert.calledWithMatch(
3392+
mockAccountEventsManager.recordSecurityEvent,
3393+
mockDB,
3394+
sinon.match({
3395+
name: 'account.signin_confirm_bypass_new_account',
3396+
uid,
3397+
ipAddr: mockRequest.app.clientAddress,
3398+
additionalInfo: {
3399+
userAgent: mockRequest.headers['user-agent'],
3400+
location: mockRequest.app.geo.location,
3401+
},
3402+
})
3403+
);
33843404
});
33853405
});
33863406

@@ -3396,6 +3416,11 @@ describe('/account/login', () => {
33963416
},
33973417
]);
33983418
});
3419+
const mockAccountEventsManager = {
3420+
recordSecurityEvent: sinon.fake(),
3421+
};
3422+
setup(true, 0, { mockAccountEventsManager });
3423+
33993424
return runTest(route, mockRequest, (response) => {
34003425
assert.equal(
34013426
mockDB.verifiedLoginSecurityEvents.callCount,
@@ -3404,6 +3429,19 @@ describe('/account/login', () => {
34043429
);
34053430

34063431
sinon.assert.called(glean.loginConfirmSkipFor.knownIp);
3432+
sinon.assert.calledWithMatch(
3433+
mockAccountEventsManager.recordSecurityEvent,
3434+
mockDB,
3435+
sinon.match({
3436+
name: 'account.signin_confirm_bypass_known_ip',
3437+
uid,
3438+
ipAddr: mockRequest.app.clientAddress,
3439+
additionalInfo: {
3440+
userAgent: mockRequest.headers['user-agent'],
3441+
location: mockRequest.app.geo.location,
3442+
},
3443+
})
3444+
);
34073445
});
34083446
});
34093447
});

packages/fxa-shared/db/models/auth/security-event.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ export const EVENT_NAMES: Record<string, number> = {
5959
'account.mfa_send_otp_code': 45,
6060
'account.mfa_verify_otp_code_success': 46,
6161
'account.mfa_verify_otp_code_failed': 47,
62+
'account.signin_confirm_bypass_known_ip': 48,
63+
'account.signin_confirm_bypass_new_account': 49,
6264
} as const;
6365

6466
export type SecurityEventNames = keyof typeof EVENT_NAMES;

0 commit comments

Comments
 (0)