Skip to content

Commit 2de2fb6

Browse files
heelc29laoneo
andauthored
[5.2] system test for multi-factor authentication (#44733)
Co-authored-by: Allon Moritz <[email protected]>
1 parent 2f06c7b commit 2de2fb6

File tree

4 files changed

+252
-2
lines changed

4 files changed

+252
-2
lines changed

package-lock.json

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"stylelint": "^14.16.1",
125125
"stylelint-config-standard": "^24.0.0",
126126
"stylelint-order": "^5.0.0",
127-
"stylelint-scss": "^4.7.0"
127+
"stylelint-scss": "^4.7.0",
128+
"totp-generator": "^1.0.0"
128129
}
129130
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { TOTP } from 'totp-generator';
2+
3+
afterEach(() => cy.db_getUserId().then((uid) => cy.task('queryDB', `DELETE FROM #__user_mfa WHERE user_id = ${uid}`)));
4+
5+
describe('Test in backend that the user', () => {
6+
it('can login with Multi-factor Authentication (email)', () => {
7+
cy.doAdministratorLogin();
8+
cy.visit('/administrator/index.php?option=com_users&view=users');
9+
cy.get('.header-profile:visible').click();
10+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
11+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
12+
cy.task('clearEmails');
13+
cy.get('.com-users-methods-list-method-name-email a.com-users-methods-list-method-addnew').click();
14+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
15+
cy.task('getMails').then((mails) => {
16+
cy.wrap(mails).should('have.lengthOf', 1);
17+
cy.wrap(mails[0].headers.subject).should('match', /code is -\d{6}-$/);
18+
cy.wrap(/code is -(\d{6})-$/.exec(mails[0].headers.subject)[1]).as('code')
19+
.then((code) => cy.wrap(mails[0].body).should('have.string', `Your authentication code is ${code}.`));
20+
cy.wrap(mails[0].html).should('be.false');
21+
});
22+
cy.get('@code').then((code) => cy.get('#com-users-method-code').clear().type(code));
23+
cy.get('#com-users-method-edit').submit();
24+
cy.get('.com-users-methods-list-method-name-email .com-users-methods-list-method-record').contains('Test Code');
25+
cy.clickToolbarButton('Cancel');
26+
cy.doAdministratorLogout();
27+
cy.get('#mod-login-username').type(Cypress.env('username'));
28+
cy.get('#mod-login-password').type(Cypress.env('password'));
29+
cy.get('#form-login').submit();
30+
cy.get('#users-mfa-title').contains('Test Code');
31+
cy.task('getMails').then((mails) => {
32+
cy.wrap(mails).should('have.lengthOf', 2);
33+
cy.wrap(mails[1].headers.subject).should('match', /code is -\d{6}-$/);
34+
cy.wrap(/code is -(\d{6})-$/.exec(mails[1].headers.subject)[1]).as('code');
35+
});
36+
cy.get('@code').then((code) => cy.get('#users-mfa-code').clear().type(code));
37+
cy.get('#users-mfa-captive-form').submit();
38+
cy.visit('/administrator/index.php?option=com_users&view=users');
39+
cy.get('.header-profile:visible').click();
40+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
41+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
42+
cy.get('#com-users-methods-reset-message').contains('is enabled');
43+
cy.get('.com-users-methods-list-method-name-email a.com-users-methods-list-method-record-delete').click();
44+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
45+
cy.get('#com-users-methods-reset-message').contains('not enabled');
46+
});
47+
48+
it('can login with Multi-factor Authentication (totp)', () => {
49+
cy.doAdministratorLogin();
50+
cy.visit('/administrator/index.php?option=com_users&view=users');
51+
cy.get('.header-profile:visible').click();
52+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
53+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
54+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-addnew').click();
55+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
56+
cy.get('.com-users-method-edit-tabular-container table tr td')
57+
.contains('Enter this key')
58+
.next()
59+
.invoke('text')
60+
.then((key) => key.trim())
61+
.as('secret');
62+
cy.get('@secret').then((secret) => cy.get('#com-users-method-code').clear().type(TOTP.generate(secret).otp));
63+
cy.get('#com-users-method-edit').submit();
64+
cy.get('.com-users-methods-list-method-name-totp .com-users-methods-list-method-record').contains('Test Code');
65+
cy.clickToolbarButton('Cancel');
66+
cy.doAdministratorLogout();
67+
cy.get('#mod-login-username').type(Cypress.env('username'));
68+
cy.get('#mod-login-password').type(Cypress.env('password'));
69+
cy.get('#form-login').submit();
70+
cy.get('#users-mfa-title').contains('Verification code');
71+
cy.get('@secret').then((secret) => cy.get('#users-mfa-code').clear().type(TOTP.generate(secret).otp));
72+
cy.get('#users-mfa-captive-form').submit();
73+
cy.visit('/administrator/index.php?option=com_users&view=users');
74+
cy.get('.header-profile:visible').click();
75+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
76+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
77+
cy.get('#com-users-methods-reset-message').contains('is enabled');
78+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-record-delete').click();
79+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
80+
cy.get('#com-users-methods-reset-message').contains('not enabled');
81+
});
82+
83+
it('can login with Multi-factor Authentication (backup codes)', () => {
84+
cy.doAdministratorLogin();
85+
cy.visit('/administrator/index.php?option=com_users&view=users');
86+
cy.get('.header-profile:visible').click();
87+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
88+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
89+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-addnew').click();
90+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
91+
cy.get('.com-users-method-edit-tabular-container table tr td')
92+
.contains('Enter this key')
93+
.next()
94+
.invoke('text')
95+
.then((key) => key.trim())
96+
.as('secret');
97+
cy.get('@secret').then((secret) => cy.get('#com-users-method-code').clear().type(TOTP.generate(secret).otp));
98+
cy.get('#com-users-method-edit').submit();
99+
cy.get('.com-users-methods-list-method-name-totp .com-users-methods-list-method-record').contains('Test Code');
100+
cy.get('.com-users-methods-list-method-name-backupcodes .com-users-methods-list-method-record-info a')
101+
.should('have.text', 'Print these codes')
102+
.click();
103+
cy.get('table > tbody > tr > td').first().invoke('text').then((code) => cy.wrap(/\d{8}/.exec(code)[0]).as('code'));
104+
cy.get('#toolbar-user-mfa-edit-cancel').contains('Back').click();
105+
cy.clickToolbarButton('Cancel');
106+
cy.doAdministratorLogout();
107+
cy.get('#mod-login-username').type(Cypress.env('username'));
108+
cy.get('#mod-login-password').type(Cypress.env('password'));
109+
cy.get('#form-login').submit();
110+
cy.get('#users-mfa-title').contains('Verification code');
111+
cy.get('#toolbar-user-mfa-choose-another').click();
112+
cy.get('a.com-users-method').contains('Backup Codes').click();
113+
cy.get('#users-mfa-title').contains('Backup Codes');
114+
cy.get('@code').then((code) => cy.get('#users-mfa-code').clear().type(code));
115+
cy.get('#users-mfa-captive-form').submit();
116+
cy.visit('/administrator/index.php?option=com_users&view=users');
117+
cy.get('.header-profile:visible').click();
118+
cy.get('.header-profile a.dropdown-item').contains('Edit Account').click();
119+
cy.get('#myTab div[role="tablist"] button[aria-controls="multifactorauth"]').click();
120+
cy.get('#com-users-methods-reset-message').contains('is enabled');
121+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-record-delete').click();
122+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
123+
cy.get('#com-users-methods-reset-message').contains('not enabled');
124+
});
125+
});
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { TOTP } from 'totp-generator';
2+
3+
afterEach(() => cy.db_getUserId().then((uid) => cy.task('queryDB', `DELETE FROM #__user_mfa WHERE user_id = ${uid}`)));
4+
5+
describe('Test in frontend that the user', () => {
6+
it('can login with Multi-factor Authentication (email)', () => {
7+
cy.doFrontendLogin();
8+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
9+
cy.task('clearEmails');
10+
cy.get('.com-users-methods-list-method-name-email a.com-users-methods-list-method-addnew').click();
11+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
12+
cy.task('getMails').then((mails) => {
13+
cy.wrap(mails).should('have.lengthOf', 1);
14+
cy.wrap(mails[0].headers.subject).should('match', /code is -\d{6}-$/);
15+
cy.wrap(/code is -(\d{6})-$/.exec(mails[0].headers.subject)[1]).as('code')
16+
.then((code) => cy.wrap(mails[0].body).should('have.string', `Your authentication code is ${code}.`));
17+
cy.wrap(mails[0].html).should('be.false');
18+
});
19+
cy.get('@code').then((code) => cy.get('#com-users-method-code').clear().type(code));
20+
cy.get('#com-users-method-edit').submit();
21+
cy.get('.com-users-methods-list-method-name-email .com-users-methods-list-method-record').contains('Test Code');
22+
cy.doFrontendLogout();
23+
cy.get('form.mod-login input[name="username"]').type(Cypress.env('username'));
24+
cy.get('form.mod-login input[name="password"]').type(Cypress.env('password'));
25+
cy.get('form.mod-login').submit();
26+
cy.get('#users-mfa-title').contains('Test Code');
27+
cy.task('getMails').then((mails) => {
28+
cy.wrap(mails).should('have.lengthOf', 2);
29+
cy.wrap(mails[1].headers.subject).should('match', /code is -\d{6}-$/);
30+
cy.wrap(/code is -(\d{6})-$/.exec(mails[1].headers.subject)[1]).as('code');
31+
});
32+
cy.get('@code').then((code) => cy.get('#users-mfa-code').clear().type(code));
33+
cy.get('#users-mfa-captive-form').submit();
34+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
35+
cy.get('#com-users-methods-reset-message').contains('is enabled');
36+
cy.get('.com-users-methods-list-method-name-email a.com-users-methods-list-method-record-delete').click();
37+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
38+
cy.get('#com-users-methods-reset-message').contains('not enabled');
39+
});
40+
41+
it('can login with Multi-factor Authentication (totp)', () => {
42+
cy.doFrontendLogin();
43+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
44+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-addnew').click();
45+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
46+
cy.get('.com-users-method-edit-tabular-container table tr td')
47+
.contains('Enter this key')
48+
.next()
49+
.invoke('text')
50+
.then((key) => key.trim())
51+
.as('secret');
52+
cy.get('@secret').then((secret) => cy.get('#com-users-method-code').clear().type(TOTP.generate(secret).otp));
53+
cy.get('#com-users-method-edit').submit();
54+
cy.get('.com-users-methods-list-method-name-totp .com-users-methods-list-method-record').contains('Test Code');
55+
cy.doFrontendLogout();
56+
cy.get('form.mod-login input[name="username"]').type(Cypress.env('username'));
57+
cy.get('form.mod-login input[name="password"]').type(Cypress.env('password'));
58+
cy.get('form.mod-login').submit();
59+
cy.get('#users-mfa-title').contains('Verification code');
60+
cy.get('@secret').then((secret) => cy.get('#users-mfa-code').clear().type(TOTP.generate(secret).otp));
61+
cy.get('#users-mfa-captive-form').submit();
62+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
63+
cy.get('#com-users-methods-reset-message').contains('is enabled');
64+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-record-delete').click();
65+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
66+
cy.get('#com-users-methods-reset-message').contains('not enabled');
67+
});
68+
69+
it('can login with Multi-factor Authentication (backup codes)', () => {
70+
cy.doFrontendLogin();
71+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
72+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-addnew').click();
73+
cy.get('#com-users-method-edit-title').clear().type('Test Code');
74+
cy.get('.com-users-method-edit-tabular-container table tr td')
75+
.contains('Enter this key')
76+
.next()
77+
.invoke('text')
78+
.then((key) => key.trim())
79+
.as('secret');
80+
cy.get('@secret').then((secret) => cy.get('#com-users-method-code').clear().type(TOTP.generate(secret).otp));
81+
cy.get('#com-users-method-edit').submit();
82+
cy.get('.com-users-methods-list-method-name-totp .com-users-methods-list-method-record').contains('Test Code');
83+
cy.get('.com-users-methods-list-method-name-backupcodes .com-users-methods-list-method-record-info a')
84+
.should('have.text', 'Print these codes')
85+
.click();
86+
cy.get('table > tbody > tr > td').first().invoke('text').then((code) => cy.wrap(/\d{8}/.exec(code)[0]).as('code'));
87+
cy.doFrontendLogout();
88+
cy.get('form.mod-login input[name="username"]').type(Cypress.env('username'));
89+
cy.get('form.mod-login input[name="password"]').type(Cypress.env('password'));
90+
cy.get('form.mod-login').submit();
91+
cy.get('#users-mfa-title').contains('Verification code');
92+
cy.get('#users-mfa-captive-form-choose-another a').click();
93+
cy.get('a.com-users-method').contains('Backup Codes').click();
94+
cy.get('#users-mfa-title').contains('Backup Codes');
95+
cy.get('@code').then((code) => cy.get('#users-mfa-code').clear().type(code));
96+
cy.get('#users-mfa-captive-form').submit();
97+
cy.visit('/index.php?option=com_users&view=profile&layout=edit');
98+
cy.get('#com-users-methods-reset-message').contains('is enabled');
99+
cy.get('.com-users-methods-list-method-name-totp a.com-users-methods-list-method-record-delete').click();
100+
cy.on('window:confirm', (text) => expect(text).to.contains('Are you sure you want to delete?'));
101+
cy.get('#com-users-methods-reset-message').contains('not enabled');
102+
});
103+
});

0 commit comments

Comments
 (0)