diff --git a/src/app/accounts/accountsLoginController.js b/src/app/accounts/accountsLoginController.js index 827b69985d0..fabf0d6ee27 100644 --- a/src/app/accounts/accountsLoginController.js +++ b/src/app/accounts/accountsLoginController.js @@ -1,7 +1,8 @@ angular .module('bit.accounts') - .controller('accountsLoginController', function ($scope, $rootScope, $cookies, apiService, cryptoService, authService, $state, appSettings, $analytics) { + .controller('accountsLoginController', function ($scope, $rootScope, $cookies, apiService, cryptoService, authService, + $state, appSettings, $analytics) { var rememberedEmail = $cookies.get(appSettings.rememberedEmailCookieName); if (rememberedEmail) { $scope.model = { @@ -10,10 +11,13 @@ angular }; } + var email, + masterPassword; + $scope.login = function (model) { $scope.loginPromise = authService.logIn(model.email, model.masterPassword); - $scope.loginPromise.then(function () { + $scope.loginPromise.then(function (twoFactorProviders) { if (model.rememberEmail) { var cookieExpiration = new Date(); cookieExpiration.setFullYear(cookieExpiration.getFullYear() + 10); @@ -27,8 +31,10 @@ angular $cookies.remove(appSettings.rememberedEmailCookieName); } - var profile = authService.getUserProfile(); - if (profile.twoFactor) { + if (twoFactorProviders && twoFactorProviders.length > 0) { + email = model.email; + masterPassword = model.masterPassword; + $analytics.eventTrack('Logged In To Two-step'); $state.go('frontend.login.twoFactor'); } @@ -40,8 +46,8 @@ angular }; $scope.twoFactor = function (model) { - // Only supporting Authenticator provider for now - $scope.twoFactorPromise = authService.logInTwoFactor(model.code, "Authenticator"); + // Only supporting Authenticator (0) provider for now + $scope.twoFactorPromise = authService.logIn(email, masterPassword, model.code, 'Authenticator'); $scope.twoFactorPromise.then(function () { $analytics.eventTrack('Logged In From Two-step'); diff --git a/src/app/config.js b/src/app/config.js index 215fb0f1f7d..1334a7b8b3c 100644 --- a/src/app/config.js +++ b/src/app/config.js @@ -2,11 +2,38 @@ angular .module('bit') .config(function ($stateProvider, $urlRouterProvider, $httpProvider, jwtInterceptorProvider, $uibTooltipProvider, toastrConfig) { - jwtInterceptorProvider.urlParam = 'access_token'; - jwtInterceptorProvider.tokenGetter = /*@ngInject*/ function (config, appSettings, tokenService) { - if (config.url.indexOf(appSettings.apiUri) === 0) { - return tokenService.getToken(); + var refreshingToken = null; + jwtInterceptorProvider.urlParam = 'access_token2'; + jwtInterceptorProvider.tokenGetter = /*@ngInject*/ function (config, appSettings, tokenService, apiService, jwtHelper) { + if (config.url.indexOf(appSettings.apiUri) !== 0) { + return; } + + var token = tokenService.getToken(); + var refreshToken = tokenService.getRefreshToken(); + if (!token) { + return; + } + + if (!jwtHelper.isTokenExpired(tokenService.getToken())) { + return token; + } + + if (refreshingToken === null) { + refreshingToken = apiService.identity.token({ + grant_type: 'refresh_token', + client_id: 'web', + refresh_token: refreshToken + }, function (response) { + tokenService.setToken(response.access_token); + tokenService.setRefreshToken(response.refresh_token); + refreshingToken = null; + }, function () { + refreshingToken = null; + }); + } + + return refreshingToken; }; angular.extend(toastrConfig, { @@ -129,7 +156,7 @@ angular .run(function ($rootScope, authService, jwtHelper, tokenService, $state) { $rootScope.$on('$stateChangeStart', function (event, toState, toParams) { if (!toState.data || !toState.data.authorize) { - if (authService.isAuthenticated() && !jwtHelper.isTokenExpired(tokenService.getToken())) { + if (authService.isAuthenticated()) { event.preventDefault(); $state.go('backend.vault'); } @@ -137,7 +164,7 @@ angular return; } - if (!authService.isAuthenticated() || jwtHelper.isTokenExpired(tokenService.getToken())) { + if (!authService.isAuthenticated()) { event.preventDefault(); authService.logOut(); $state.go('frontend.login.info'); diff --git a/src/app/services/apiService.js b/src/app/services/apiService.js index 2bb1fc0fec1..51cedc85d4a 100644 --- a/src/app/services/apiService.js +++ b/src/app/services/apiService.js @@ -1,7 +1,7 @@ angular .module('bit.services') - .factory('apiService', function ($resource, tokenService, appSettings) { + .factory('apiService', function ($resource, tokenService, appSettings, $httpParamSerializer) { var _service = {}, _apiUri = appSettings.apiUri; @@ -57,5 +57,19 @@ tokenTwoFactor: { url: _apiUri + '/auth/token/two-factor', method: 'POST', params: {} } }); + _service.identity = $resource(_apiUri + '/connect', {}, { + token: { + url: _apiUri + '/connect/token', + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }, + transformRequest: transformUrlEncoded, + params: {} + } + }); + + function transformUrlEncoded(data) { + return $httpParamSerializer(data); + } + return _service; }); diff --git a/src/app/services/authService.js b/src/app/services/authService.js index 7794a8803d5..fb98f5e10cd 100644 --- a/src/app/services/authService.js +++ b/src/app/services/authService.js @@ -5,51 +5,42 @@ angular var _service = {}, _userProfile = null; - _service.logIn = function (email, masterPassword) { + _service.logIn = function (email, masterPassword, token, provider) { email = email.toLowerCase(); var key = cryptoService.makeKey(masterPassword, email); var request = { - email: email, - masterPasswordHash: cryptoService.hashPassword(masterPassword, key) + username: email, + password: cryptoService.hashPassword(masterPassword, key), + grant_type: 'password', + scope: 'api offline_access', + client_id: 'web' }; + if (token && typeof (provider) !== 'undefined' && provider !== null) { + request.twoFactorToken = token.replace(' ', ''); + request.twoFactorProvider = provider; + } + + // TODO: device information one day? + var deferred = $q.defer(); - apiService.auth.token(request, function (response) { - if (!response || !response.Token) { + apiService.identity.token(request, function (response) { + if (!response || !response.access_token) { return; } - tokenService.setToken(response.Token); + tokenService.setToken(response.access_token); + tokenService.setRefreshToken(response.refresh_token); cryptoService.setKey(key); - _service.setUserProfile(response.Profile); - - deferred.resolve(response); + deferred.resolve(); }, function (error) { - deferred.reject(error); - }); - - return deferred.promise; - }; - - _service.logInTwoFactor = function (code, provider) { - var request = { - code: code.replace(' ', ''), - provider: provider - }; - - var deferred = $q.defer(); - apiService.auth.tokenTwoFactor(request, function (response) { - if (!response || !response.Token) { - return; + if (error.status === 400 && error.data.TwoFactorProviders && error.data.TwoFactorProviders.length) { + deferred.resolve(error.data.TwoFactorProviders); + } + else { + deferred.reject(error); } - - tokenService.setToken(response.Token); - _service.setUserProfile(response.Profile); - - deferred.resolve(response); - }, function (error) { - deferred.reject(error); }); return deferred.promise; @@ -57,6 +48,7 @@ angular _service.logOut = function () { tokenService.clearToken(); + tokenService.clearRefreshToken(); cryptoService.clearKey(); _userProfile = null; }; @@ -69,27 +61,20 @@ angular return _userProfile; }; - _service.setUserProfile = function (profile) { + _service.setUserProfile = function () { var token = tokenService.getToken(); if (!token) { return; } var decodedToken = jwtHelper.decodeToken(token); - var twoFactor = decodedToken.authmethod === "TwoFactor"; _userProfile = { - id: decodedToken.nameid, - email: decodedToken.email, - twoFactor: twoFactor + id: decodedToken.name, + email: decodedToken.email }; - if (!twoFactor && profile) { - loadProfile(profile); - } - else if (!twoFactor && !profile) { - apiService.accounts.getProfile({}, loadProfile); - } + apiService.accounts.getProfile({}, loadProfile); }; function loadProfile(profile) { @@ -101,11 +86,7 @@ angular } _service.isAuthenticated = function () { - return _service.getUserProfile() !== null && !_service.getUserProfile().twoFactor; - }; - - _service.isTwoFactorAuthenticated = function () { - return _service.getUserProfile() !== null && _service.getUserProfile().twoFactor; + return tokenService.getToken() !== null; }; return _service; diff --git a/src/app/services/tokenService.js b/src/app/services/tokenService.js index 37cd6b43590..a1583694fed 100644 --- a/src/app/services/tokenService.js +++ b/src/app/services/tokenService.js @@ -3,24 +3,43 @@ angular .factory('tokenService', function ($sessionStorage) { var _service = {}, - _token; + _token = null, + _refreshToken = null; _service.setToken = function (token) { - $sessionStorage.authBearer = token; + $sessionStorage.accessToken = token; _token = token; }; _service.getToken = function () { if (!_token) { - _token = $sessionStorage.authBearer; + _token = $sessionStorage.accessToken; } - return _token; + return _token ? _token : null; }; _service.clearToken = function () { _token = null; - delete $sessionStorage.authBearer; + delete $sessionStorage.accessToken; + }; + + _service.setRefreshToken = function (token) { + $sessionStorage.refreshToken = token; + _refreshToken = token; + }; + + _service.getRefreshToken = function () { + if (!_refreshToken) { + _refreshToken = $sessionStorage.refreshToken; + } + + return _refreshToken ? _refreshToken : null; + }; + + _service.clearRefreshToken = function () { + _refreshToken = null; + delete $sessionStorage.refreshToken; }; return _service; diff --git a/src/app/services/validationService.js b/src/app/services/validationService.js index 1015c98fd2a..f448b7f94a5 100644 --- a/src/app/services/validationService.js +++ b/src/app/services/validationService.js @@ -14,6 +14,10 @@ return; } + if (data && data.ErrorModel) { + data = data.ErrorModel; + } + if (!data.ValidationErrors) { if (data.Message) { form.$errors.push(data.Message);