From 0a439b3893808ee603d478762ff89b9b2b94b87b Mon Sep 17 00:00:00 2001 From: Chaim Lev Ari Date: Wed, 16 Jan 2019 18:57:15 +0200 Subject: [PATCH] refactor(auth): extract oauth login mechanism to service --- .../oauth/services/oauth-service.js | 53 +++++++++++++++++++ app/portainer/helpers/urlHelper.js | 8 +-- app/portainer/services/authentication.js | 14 ++--- app/portainer/views/auth/auth.html | 8 ++- app/portainer/views/auth/authController.js | 32 ++++++----- 5 files changed, 83 insertions(+), 32 deletions(-) create mode 100644 app/extensions/oauth/services/oauth-service.js diff --git a/app/extensions/oauth/services/oauth-service.js b/app/extensions/oauth/services/oauth-service.js new file mode 100644 index 000000000..d1985c693 --- /dev/null +++ b/app/extensions/oauth/services/oauth-service.js @@ -0,0 +1,53 @@ +angular.module('portainer.extensions.oauth').service('OAuthService', [ + 'SettingsService', 'OAuth', 'urlHelper', + function OAuthService(SettingsService, OAuth, urlHelper) { + this.login = login; + + function login() { + return getLoginURI() + .then(function openPopup(loginUrl) { + var popup = window.open(loginUrl, 'login-popup', 'width=800, height=600'); + if (!popup) { + throw new Error('Please enable popups for this page'); + } + return waitForCode(popup); + }) + .then(function onCodeReady(code) { + return OAuth.login({ code: code }).$promise; + }); + } + + function getLoginURI() { + return SettingsService.publicSettings().then(function onLoadSettings(settings) { + if (settings.AuthenticationMethod !== 3) { + throw new Error('OAuth is disabled'); + } + return settings.OAuthLoginURI; + }); + } + + function waitForCode(popup) { + return waitFor(function checkIfCodeIsAvailable() { + if (popup.document.URL.indexOf('code') !== -1) { + var queryParams = popup.location.search; + popup.close(); + return urlHelper.getParameter(queryParams, 'code'); + } + }); + } + + function waitFor(clbk, interval) { + interval = interval || 100; + var intervalId; + return new Promise(function executor(resolve) { + intervalId = setInterval(function intervalFunction() { + var callbackReturn = clbk(); + if (callbackReturn) { + clearInterval(intervalId); + resolve(callbackReturn); + } + }, interval); + }); + } + } +]); diff --git a/app/portainer/helpers/urlHelper.js b/app/portainer/helpers/urlHelper.js index 3125492a5..daacf0131 100644 --- a/app/portainer/helpers/urlHelper.js +++ b/app/portainer/helpers/urlHelper.js @@ -2,13 +2,13 @@ angular.module('portainer.app').service('urlHelper', function urlHelper($window) this.getParameter = getParameter; this.cleanParameters = cleanParameters; - function getParameter(param) { - var parameters = extractParameters(); + function getParameter(queryParams, param) { + var parameters = extractParameters(queryParams); return parameters[param]; } - function extractParameters() { - var queryString = $window.location.search.replace(/.*?\?/,'').split('&'); + function extractParameters(queryParams) { + var queryString = queryParams.replace(/.*?\?/,'').split('&'); return queryString.reduce(function(acc, keyValStr) { var keyVal = keyValStr.split('='); var key = keyVal[0]; diff --git a/app/portainer/services/authentication.js b/app/portainer/services/authentication.js index 39b7ada24..ac03e1fde 100644 --- a/app/portainer/services/authentication.js +++ b/app/portainer/services/authentication.js @@ -1,7 +1,7 @@ angular.module('portainer.app') .factory('Authentication', [ -'Auth', 'OAuth', 'jwtHelper', 'LocalStorage', 'StateManager', 'EndpointProvider', -function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManager, EndpointProvider) { +'Auth', 'OAuthService', 'jwtHelper', 'LocalStorage', 'StateManager', 'EndpointProvider', +function AuthenticationFactory(Auth, OAuthService, jwtHelper, LocalStorage, StateManager, EndpointProvider) { 'use strict'; var service = {}; @@ -13,6 +13,8 @@ function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManage service.logout = logout; service.isAuthenticated = isAuthenticated; service.getUserDetails = getUserDetails; + + function init() { var jwt = LocalStorage.getJWT(); @@ -22,10 +24,10 @@ function AuthenticationFactory(Auth, OAuth, jwtHelper, LocalStorage, StateManage } } - function OAuthLogin(code) { - return OAuth.login({ code: code }).$promise - .then(function onLoginSuccess(response) { - return setUser(response.jwt); + function OAuthLogin() { + return OAuthService.login() + .then(function onLoginSuccess(loginResponse) { + setUser(loginResponse.jwt); }); } diff --git a/app/portainer/views/auth/auth.html b/app/portainer/views/auth/auth.html index 62c26d8b6..e32b7633a 100644 --- a/app/portainer/views/auth/auth.html +++ b/app/portainer/views/auth/auth.html @@ -28,11 +28,9 @@
- -
- Login with OAuth -
-
+ diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js index fb8968e48..575ecdc6a 100644 --- a/app/portainer/views/auth/authController.js +++ b/app/portainer/views/auth/authController.js @@ -1,6 +1,6 @@ angular.module('portainer.app') -.controller('AuthenticationController', ['urlHelper','$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'StateManager', 'Notifications', 'SettingsService', -function (urlHelper, $q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, StateManager, Notifications, SettingsService) { +.controller('AuthenticationController', ['$q', '$scope', '$state', '$stateParams', '$sanitize', 'Authentication', 'UserService', 'EndpointService', 'StateManager', 'Notifications', 'SettingsService', +function ($q, $scope, $state, $stateParams, $sanitize, Authentication, UserService, EndpointService, StateManager, Notifications, SettingsService) { $scope.logo = StateManager.getState().application.logo; $scope.formValues = { @@ -37,6 +37,17 @@ function (urlHelper, $q, $scope, $state, $stateParams, $sanitize, Authentication }); }; + $scope.oauthLogin = function oauthLogin() { + return Authentication.OAuthLogin() + .then(function onLoginSuccess() { + return $state.go('portainer.home'); + }) + .catch(function onError(error) { + $scope.state.AuthenticationError = error.message; + }); + }; + + function unauthenticatedFlow() { EndpointService.endpoints() .then(function success(endpoints) { @@ -104,23 +115,10 @@ function (urlHelper, $q, $scope, $state, $stateParams, $sanitize, Authentication authenticatedFlow(); } - var code = urlHelper.getParameter('code'); - if (code) { - oAuthLogin(code); - } - } - - function oAuthLogin(code) { - return Authentication.OAuthLogin(code) - .then(function success() { - urlHelper.cleanParameters(); - $state.go('portainer.home'); - }) - .catch(function error() { - $scope.state.AuthenticationError = 'Failed to authenticate with OAuth2 Provider'; - }); + } + initView(); }]);