accounts-frontend/tests-e2e/cypress/integration/auth/oauth.test.ts

461 lines
16 KiB
TypeScript
Raw Normal View History

import { account1 } from '../../fixtures/accounts.json';
import { UserResponse } from 'app/services/api/accounts';
const defaults = {
2020-05-24 04:38:24 +05:30
client_id: 'ely',
redirect_uri: 'https://dev.ely.by/authorization/oauth',
response_type: 'code',
scope: 'account_info,account_email',
};
2019-12-28 15:55:44 +05:30
describe('OAuth', () => {
2020-05-24 04:38:24 +05:30
it('should complete oauth', () => {
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
2020-01-10 17:57:20 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
2020-05-24 04:38:24 +05:30
});
it('should not complete oauth if account is deleted', () => {
cy.login({ accounts: ['default'] });
cy.server();
cy.route({
method: 'GET',
url: `/api/v1/accounts/${account1.id}`,
response: {
id: 7,
uuid: '522e8c19-89d8-4a6d-a2ec-72ebb58c2dbe',
username: 'SleepWalker',
isOtpEnabled: false,
registeredAt: 1475568334,
lang: 'en',
elyProfileLink: 'http://ely.by/u7',
email: 'danilenkos@auroraglobal.com',
isActive: true,
isDeleted: true, // force user into the deleted state
passwordChangedAt: 1476075696,
hasMojangUsernameCollision: true,
shouldAcceptRules: false,
} as UserResponse,
});
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
cy.location('pathname').should('eq', '/');
cy.findByTestId('deletedAccount').should('contain', 'Account is deleted');
});
2020-05-24 04:38:24 +05:30
it('should restore previous oauthData if any', () => {
localStorage.setItem(
'oauthData',
JSON.stringify({
timestamp: Date.now() - 3600,
payload: {
clientId: 'ely',
redirectUrl: 'https://dev.ely.by/authorization/oauth',
responseType: 'code',
description: null,
scope: 'account_info account_email',
loginHint: null,
state: null,
},
}),
);
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit('/');
2020-05-24 04:38:24 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
});
2020-05-24 04:38:24 +05:30
it('should ask to choose an account if user has multiple', () => {
cy.login({ accounts: ['default', 'default2'] }).then(({ accounts: [account] }) => {
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/choose-account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-header').should('contain', 'Choose an account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-body').contains(account.email).click();
2020-05-24 04:38:24 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
});
});
2020-05-24 04:38:24 +05:30
// TODO: remove api mocks, when we will be able to revoke permissions
it('should prompt for permissions', () => {
cy.server();
cy.route({
method: 'POST',
// NOTE: can not use cypress glob syntax, because it will break due to
// '%2F%2F' (//) in redirect_uri
// url: '/api/oauth2/v1/complete/*',
url: new RegExp('/api/oauth2/v1/complete'),
response: {
statusCode: 401,
error: 'accept_required',
},
status: 401,
}).as('complete');
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
})}`,
);
2020-05-24 04:38:24 +05:30
cy.wait('@complete');
2020-05-24 04:38:24 +05:30
assertPermissions();
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
cy.server({ enable: false });
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls').contains('Approve').click();
2020-05-24 04:38:24 +05:30
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
});
2020-05-24 04:38:24 +05:30
it('should allow sign in during oauth (guest oauth)', () => {
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/login');
2020-05-24 04:38:24 +05:30
cy.get('[name=login]').type(`${account1.login}{enter}`);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/password');
2020-05-24 04:38:24 +05:30
cy.get('[name=password]').type(`${account1.password}{enter}`);
2020-05-24 04:38:24 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
2019-12-28 15:55:44 +05:30
});
it('should allow sign in during oauth and not finish process if the account is deleted', () => {
cy.visit(`/oauth2/v1/ely?${new URLSearchParams(defaults)}`);
cy.url().should('include', '/login');
cy.get('[name=login]').type(`${account1.login}{enter}`);
cy.url().should('include', '/password');
cy.server();
cy.route({
method: 'GET',
url: `/api/v1/accounts/${account1.id}`,
response: {
id: 7,
uuid: '522e8c19-89d8-4a6d-a2ec-72ebb58c2dbe',
username: 'SleepWalker',
isOtpEnabled: false,
registeredAt: 1475568334,
lang: 'en',
elyProfileLink: 'http://ely.by/u7',
email: 'danilenkos@auroraglobal.com',
isActive: true,
isDeleted: true, // force user into the deleted state
passwordChangedAt: 1476075696,
hasMojangUsernameCollision: true,
shouldAcceptRules: false,
} as UserResponse,
});
cy.get('[name=password]').type(`${account1.password}{enter}`);
cy.location('pathname').should('eq', '/');
cy.findByTestId('deletedAccount').should('contain', 'Account is deleted');
});
2020-05-24 04:38:24 +05:30
// TODO: enable, when backend api will return correct response on auth decline
xit('should redirect to error page, when permission request declined', () => {
cy.server();
cy.route({
method: 'POST',
// NOTE: can not use cypress glob syntax, because it will break due to
// '%2F%2F' (//) in redirect_uri
// url: '/api/oauth2/v1/complete/*',
url: new RegExp('/api/oauth2/v1/complete'),
response: {
statusCode: 401,
error: 'accept_required',
},
status: 401,
}).as('complete');
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit(
2019-12-28 15:55:44 +05:30
`/oauth2/v1/ely?${new URLSearchParams({
2020-05-24 04:38:24 +05:30
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
2019-12-28 15:55:44 +05:30
})}`,
2020-05-24 04:38:24 +05:30
);
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
cy.wait('@complete');
2020-05-24 04:38:24 +05:30
assertPermissions();
2020-05-24 04:38:24 +05:30
cy.server({ enable: false });
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls-secondary').contains('Decline').click();
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
cy.url().should('include', 'error=access_denied');
});
2020-05-24 04:38:24 +05:30
describe('login_hint', () => {
it('should automatically choose account, when id in login_hint is present', () => {
cy.login({ accounts: ['default', 'default2'] }).then(({ accounts: [account] }) => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
// suggest preferred username
// https://docs.ely.by/ru/oauth.html#id3
login_hint: String(account.id),
}).toString()}`,
);
cy.url().should('equal', 'https://dev.ely.by/');
});
});
it('should automatically choose account, when email in login_hint is present', () => {
cy.login({ accounts: ['default', 'default2'] }).then(({ accounts: [account] }) => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
// suggest preferred username
// https://docs.ely.by/ru/oauth.html#id3
login_hint: account.email,
})}`,
);
cy.url().should('equal', 'https://dev.ely.by/');
});
});
it('should automatically choose account, when username in login_hint is present and it is not an active account', () => {
cy.login({ accounts: ['default2', 'default'] }).then(
({
// try to authenticate with an account, that is not currently active one
accounts: [, account],
}) => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
// suggest preferred username
// https://docs.ely.by/ru/oauth.html#id3
login_hint: account.username,
})}`,
);
cy.url().should('equal', 'https://dev.ely.by/');
},
);
});
2019-12-28 15:55:44 +05:30
});
2020-05-24 04:38:24 +05:30
describe('prompts', () => {
it('should prompt for account', () => {
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
prompt: 'select_account',
})}`,
);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/choose-account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-header').should('contain', 'Choose an account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-body').contains(account.email).click();
2020-05-24 04:38:24 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
});
});
2020-05-24 04:38:24 +05:30
it('should allow sign in with another account', () => {
cy.login({ accounts: ['default2'] });
2020-05-24 04:38:24 +05:30
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
prompt: 'select_account',
})}`,
);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/choose-account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls').contains('another account').click();
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/login');
2020-05-24 04:38:24 +05:30
cy.get('[name=login]').type(`${account1.login}{enter}`);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/password');
2020-05-24 04:38:24 +05:30
cy.get('[name=password]').type(`${account1.password}{enter}`);
2020-05-24 04:38:24 +05:30
cy.url().should('equal', 'https://dev.ely.by/');
});
2020-05-24 04:38:24 +05:30
it('should prompt for permissions', () => {
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
prompt: 'consent',
})}`,
);
2020-05-24 04:38:24 +05:30
assertPermissions();
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls').contains('Approve').click();
2020-05-24 04:38:24 +05:30
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
});
2020-05-24 04:38:24 +05:30
// TODO: enable, when backend api will return correct response on auth decline
xit('should redirect to error page, when permission request declined', () => {
cy.login({ accounts: ['default'] });
2020-05-24 04:38:24 +05:30
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
prompt: 'consent',
})}`,
);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/permissions');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls-secondary').contains('Decline').click();
2020-05-24 04:38:24 +05:30
cy.url().should('include', 'error=access_denied');
});
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
it('should prompt for both account and permissions', () => {
cy.login({ accounts: ['default'] }).then(({ accounts: [account] }) => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
prompt: 'select_account,consent',
})}`,
);
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/choose-account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-header').should('contain', 'Choose an account');
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-body').contains(account.email).click();
2020-05-24 04:38:24 +05:30
assertPermissions();
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls').contains('Approve').click();
2019-12-28 15:55:44 +05:30
2020-05-24 04:38:24 +05:30
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
});
});
2020-05-24 04:38:24 +05:30
it('should allow sign in during oauth (guest oauth)', () => {
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'http://localhost:8080',
prompt: 'select_account,consent',
})}`,
);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/login');
2020-05-24 04:38:24 +05:30
cy.get('[name=login]').type(`${account1.login}{enter}`);
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/password');
2019-12-29 21:56:51 +05:30
2020-05-24 04:38:24 +05:30
cy.get('[name=password]').type(`${account1.password}{enter}`);
2020-05-24 04:38:24 +05:30
assertPermissions();
2020-05-24 04:38:24 +05:30
cy.findByTestId('auth-controls').contains('Approve').click();
2019-12-29 21:56:51 +05:30
2020-05-24 04:38:24 +05:30
cy.url().should('match', /^http:\/\/localhost:8080\/?\?code=[^&]+&state=$/);
});
2019-12-28 15:55:44 +05:30
});
2020-05-24 04:38:24 +05:30
describe('static pages', () => {
it('should authenticate using static page', () => {
cy.server();
cy.route({
method: 'POST',
url: '/api/oauth2/v1/complete**',
}).as('complete');
cy.login({ accounts: ['default'] });
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'static_page',
})}`,
);
cy.wait('@complete');
cy.url().should('include', 'oauth/finish#{%22auth_code%22:');
});
it('should authenticate using static page with code', () => {
cy.server();
cy.route({
method: 'POST',
url: '/api/oauth2/v1/complete**',
}).as('complete');
cy.login({ accounts: ['default'] });
cy.visit(
`/oauth2/v1/ely?${new URLSearchParams({
...defaults,
client_id: 'tlauncher',
redirect_uri: 'static_page_with_code',
})}`,
);
cy.wait('@complete');
cy.url().should('include', 'oauth/finish#{%22auth_code%22:');
cy.findByTestId('oauth-code-container').should('contain', 'provide the following code');
// just click on copy, but we won't assert if the string was copied
// because it is a little bit complicated
// https://github.com/cypress-io/cypress/issues/2752
cy.findByTestId('oauth-code-container').contains('Copy').click();
});
2019-12-28 15:55:44 +05:30
});
});
2019-12-29 21:56:51 +05:30
function assertPermissions() {
2020-05-24 04:38:24 +05:30
cy.url().should('include', '/oauth/permissions');
cy.findByTestId('auth-header').should('contain', 'Application permissions');
cy.findByTestId('auth-body').should('contain', 'Access to your profile data (except Email)');
cy.findByTestId('auth-body').should('contain', 'Access to your Email address');
2019-12-29 21:56:51 +05:30
}