diff --git a/src/api/auth/auth.js b/src/api/auth/auth.js index 748d12f6..7597ed93 100644 --- a/src/api/auth/auth.js +++ b/src/api/auth/auth.js @@ -3,6 +3,25 @@ import instance, { config } from '../instance'; export const login = async (credentials) => { const url = '/login'; + try { + const response = await instance.post(url, credentials); + + // [https://webitel.atlassian.net/browse/WTEL-3405] + // If two-factor authentication is enabled, + // API returns the two-factor authentication session ID instead of a token + // and saving to localStorage is not needed + + if(response.accessToken) { + localStorage.setItem('access-token', response.accessToken); + return postToken(); + } return response; + } catch (err) { + throw err; + } +}; + +export const login2fa = async (credentials) => { + const url = '/login/2fa'; try { const response = await instance.post(url, credentials); localStorage.setItem('access-token', response.accessToken); @@ -105,6 +124,7 @@ const checkDomainExistence = async (domain) => { const AuthAPI = { login, + login2fa, register, checkCurrentSession, loadServiceProviders, diff --git a/src/components/auth/login/steps/the-login-third-step.vue b/src/components/auth/login/steps/the-login-third-step.vue new file mode 100644 index 00000000..ff8eeea1 --- /dev/null +++ b/src/components/auth/login/steps/the-login-third-step.vue @@ -0,0 +1,58 @@ + + + diff --git a/src/components/auth/login/the-login.vue b/src/components/auth/login/the-login.vue index f5fb7917..af307def 100644 --- a/src/components/auth/login/the-login.vue +++ b/src/components/auth/login/the-login.vue @@ -21,6 +21,12 @@ @back="backPrevStep" @next="goNextStep" > + + @@ -28,10 +34,10 @@ diff --git a/src/locale/en/en.js b/src/locale/en/en.js index 06907cc1..f192ca3f 100644 --- a/src/locale/en/en.js +++ b/src/locale/en/en.js @@ -16,6 +16,8 @@ export default { signIn: 'Sign in', login: 'Log in', remember: 'Remember', + code: 'Code', + enterAuthenticationCode: 'Enter your two-factor authentication code', carousel: { title1: 'Cloud vs. On-Site', text1: 'Security policy does not allow to store data and use cloud services? With Webitel, you can build a contact center on your site!', diff --git a/src/locale/ru/ru.js b/src/locale/ru/ru.js index 22d748aa..842b648f 100644 --- a/src/locale/ru/ru.js +++ b/src/locale/ru/ru.js @@ -16,5 +16,7 @@ export default { signIn: 'Войти', login: 'Войти', remember: 'Запомнить', + code: 'Код', + enterAuthenticationCode: 'Введите ваш код двухфакторной аутентификации', }, }; diff --git a/src/locale/ua/ua.js b/src/locale/ua/ua.js index 31fb2c3d..c309e70a 100644 --- a/src/locale/ua/ua.js +++ b/src/locale/ua/ua.js @@ -16,5 +16,7 @@ export default { signIn: 'Увійти', login: 'Увійти', remember: 'Запам\'ятати', + code: 'Код', + enterAuthenticationCode: 'Введіть ваш код двофакторної автентифікації', }, }; diff --git a/src/store/modules/auth/auth.js b/src/store/modules/auth/auth.js index d2113a0e..59573094 100644 --- a/src/store/modules/auth/auth.js +++ b/src/store/modules/auth/auth.js @@ -14,6 +14,9 @@ const state = { ...defaultState(), rememberCredentials: localStorage.getItem('auth/rememberCredentials') === 'true', loginProviders: {}, + enabledTfa: false, + totp: '', + sessionId: '', // it's necessary for two-factor authentication }; const getters = {}; @@ -21,22 +24,21 @@ const getters = {}; const actions = { SUBMIT_AUTH: async (context, action) => { let accessToken; - switch (action) { - case 'login': - accessToken = await context.dispatch('LOGIN'); - break; - case 'register': - accessToken = await context.dispatch('REGISTER'); - break; - default: - throw new Error(`Invalid action: ${action}`); - } + + if(action === 'login') { + if(context.state.sessionId) { + accessToken = await context.dispatch('LOGIN_2FA'); + } + accessToken = await context.dispatch('LOGIN'); + } else if(action === 'register') { + accessToken = await context.dispatch('REGISTER'); + } else throw new Error(`Invalid action: ${action}`); return context.dispatch('ON_AUTH_SUCCESS', { accessToken }); }, - LOGIN: (context) => { - return AuthAPI.login({ + LOGIN: async (context) => { + return await AuthAPI.login({ username: context.state.username, password: context.state.password, domain: context.state.domain, @@ -52,11 +54,31 @@ const actions = { }); }, + LOGIN_2FA: (context) => { + return AuthAPI.login2fa({ + id: context.state.sessionId, + totp: context.state.totp, + }) + }, + + GET_2FA_SESSION_ID: async (context) => { + const { id } = await AuthAPI.login({ + username: context.state.username, + password: context.state.password, + domain: context.state.domain, + }); + + if(id) { + await context.dispatch('SET_PROPERTY', { prop: 'sessionId', value: id }); + } + }, + LOAD_SERVICE_PROVIDERS: async (context) => { const domain = context.state.domain; const response = await AuthAPI.loadServiceProviders({ domain }); - const { federation = {} } = response; + const { federation = {}, enabledTfa } = response; context.commit('SET_SERVICE_PROVIDERS', federation); + await context.dispatch('SET_PROPERTY', { prop: 'enabledTfa', value: enabledTfa }); }, EXECUTE_PROVIDER: (context, { ticket }) => {