From 17645844addb353431a5a3bcd0bc97be508a6a5a Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 13:59:49 +0200 Subject: [PATCH 01/10] Added new disable-skip-button argument --- src/app/backend/args/builder.go | 6 ++++++ src/app/backend/args/holder.go | 7 +++++++ src/app/backend/auth/api/types.go | 2 ++ src/app/backend/dashboard.go | 2 ++ 4 files changed, 17 insertions(+) diff --git a/src/app/backend/args/builder.go b/src/app/backend/args/builder.go index 9966a3be916a..2470cb195cb0 100644 --- a/src/app/backend/args/builder.go +++ b/src/app/backend/args/builder.go @@ -132,6 +132,12 @@ func (self *holderBuilder) SetDisableSettingsAuthorizer(enableSettingsAuthorizer return self } +// SetDisableSkipButton 'disable-skip' argument of Dashboard binary. +func (self *holderBuilder) SetDisableSkipButton(disableSkipButton bool) *holderBuilder { + self.holder.disableSkipButton = disableSkipButton + return self +} + // GetHolderBuilder returns singletone instance of argument holder builder. func GetHolderBuilder() *holderBuilder { return builder diff --git a/src/app/backend/args/holder.go b/src/app/backend/args/holder.go index 3fb7ba05790a..7929e6b03be4 100644 --- a/src/app/backend/args/holder.go +++ b/src/app/backend/args/holder.go @@ -47,6 +47,8 @@ type holder struct { autoGenerateCertificates bool enableInsecureLogin bool disableSettingsAuthorizer bool + + disableSkipButton bool } // GetInsecurePort 'insecure-port' argument of Dashboard binary. @@ -146,3 +148,8 @@ func (self *holder) GetEnableInsecureLogin() bool { func (self *holder) GetDisableSettingsAuthorizer() bool { return self.disableSettingsAuthorizer } + +// GetDisableSettingsAuthorizer 'disable-settings-authorizer' argument of Dashboard binary. +func (self *holder) GetDisableSkipButton() bool { + return self.disableSkipButton +} diff --git a/src/app/backend/auth/api/types.go b/src/app/backend/auth/api/types.go index 489af83922f1..df01234b0d88 100644 --- a/src/app/backend/auth/api/types.go +++ b/src/app/backend/auth/api/types.go @@ -77,6 +77,8 @@ type AuthManager interface { Refresh(string) (string, error) // AuthenticationModes returns array of auth modes supported by dashboard. AuthenticationModes() []AuthenticationMode + // AuthenticationSkippable tells if the Skip button should be enabled or not + AuthenticationSkippable() bool } // TokenManager is responsible for generating and decrypting tokens used for authorization. Authorization is handled diff --git a/src/app/backend/dashboard.go b/src/app/backend/dashboard.go index 1d37e46292e5..cb9579214c8d 100644 --- a/src/app/backend/dashboard.go +++ b/src/app/backend/dashboard.go @@ -66,6 +66,7 @@ var ( argMetricClientCheckPeriod = pflag.Int("metric-client-check-period", 30, "Time in seconds that defines how often configured metric client health check should be run. Default: 30 seconds.") argAutoGenerateCertificates = pflag.Bool("auto-generate-certificates", false, "When set to true, Dashboard will automatically generate certificates used to serve HTTPS. Default: false.") argEnableInsecureLogin = pflag.Bool("enable-insecure-login", false, "When enabled, Dashboard login view will also be shown when Dashboard is not served over HTTPS. Default: false.") + argDisableSkip = pflag.Bool("disable-skip", false, "When enabled, the skip button on the login page will not be shown. Default: false.") argSystemBanner = pflag.String("system-banner", "", "When non-empty displays message to Dashboard users. Accepts simple HTML tags. Default: ''.") argSystemBannerSeverity = pflag.String("system-banner-severity", "INFO", "Severity of system banner. Should be one of 'INFO|WARNING|ERROR'. Default: 'INFO'.") argDisableSettingsAuthorizer = pflag.Bool("disable-settings-authorizer", false, "When enabled, Dashboard settings page will not require user to be logged in and authorized to access settings page.") @@ -217,6 +218,7 @@ func initArgHolder() { builder.SetAutoGenerateCertificates(*argAutoGenerateCertificates) builder.SetEnableInsecureLogin(*argEnableInsecureLogin) builder.SetDisableSettingsAuthorizer(*argDisableSettingsAuthorizer) + builder.SetDisableSkipButton(*argDisableSkip) } /** From bb3209716dae4bd60e710a3a1d0b7b349f9b9176 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:02:22 +0200 Subject: [PATCH 02/10] Added skip button enable backend API --- src/app/backend/auth/api/types.go | 6 ++++++ src/app/backend/auth/handler.go | 8 ++++++++ src/app/backend/auth/manager.go | 20 +++++++++++++------- src/app/backend/dashboard.go | 5 ++++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/app/backend/auth/api/types.go b/src/app/backend/auth/api/types.go index df01234b0d88..0f74167e228b 100644 --- a/src/app/backend/auth/api/types.go +++ b/src/app/backend/auth/api/types.go @@ -138,3 +138,9 @@ type TokenRefreshSpec struct { type LoginModesResponse struct { Modes []AuthenticationMode `json:"modes"` } + +// LoginSkippableResponse contains a flag that tells the UI not to display the Skip button. +// Note that this only hides the button, it doesn't disable unauthenticated access. +type LoginSkippableResponse struct { + Skippable bool `json:"skippable"` +} diff --git a/src/app/backend/auth/handler.go b/src/app/backend/auth/handler.go index a3ef7e948b34..2d98b14528bf 100644 --- a/src/app/backend/auth/handler.go +++ b/src/app/backend/auth/handler.go @@ -48,6 +48,10 @@ func (self AuthHandler) Install(ws *restful.WebService) { ws.GET("/login/modes"). To(self.handleLoginModes). Writes(authApi.LoginModesResponse{})) + ws.Route( + ws.GET("/login/skippable"). + To(self.handleLoginSkippable). + Writes(authApi.LoginSkippableResponse{})) } func (self AuthHandler) handleLogin(request *restful.Request, response *restful.Response) { @@ -97,6 +101,10 @@ func (self *AuthHandler) handleLoginModes(request *restful.Request, response *re response.WriteHeaderAndEntity(http.StatusOK, authApi.LoginModesResponse{Modes: self.manager.AuthenticationModes()}) } +func (self *AuthHandler) handleLoginSkippable(request *restful.Request, response *restful.Response) { + response.WriteHeaderAndEntity(http.StatusOK, authApi.LoginSkippableResponse{Skippable: self.manager.AuthenticationSkippable()}) +} + // NewAuthHandler created AuthHandler instance. func NewAuthHandler(manager authApi.AuthManager) AuthHandler { return AuthHandler{manager: manager} diff --git a/src/app/backend/auth/manager.go b/src/app/backend/auth/manager.go index a46414b7840b..c74a5180a5fb 100644 --- a/src/app/backend/auth/manager.go +++ b/src/app/backend/auth/manager.go @@ -25,9 +25,10 @@ import ( // Implements AuthManager interface type authManager struct { - tokenManager authApi.TokenManager - clientManager clientapi.ClientManager - authenticationModes authApi.AuthenticationModes + tokenManager authApi.TokenManager + clientManager clientapi.ClientManager + authenticationModes authApi.AuthenticationModes + authenticationSkippable bool } // Login implements auth manager. See AuthManager interface for more information. @@ -65,6 +66,10 @@ func (self authManager) AuthenticationModes() []authApi.AuthenticationMode { return self.authenticationModes.Array() } +func (self authManager) AuthenticationSkippable() bool { + return self.authenticationSkippable +} + // Returns authenticator based on provided LoginSpec. func (self authManager) getAuthenticator(spec *authApi.LoginSpec) (authApi.Authenticator, error) { if len(self.authenticationModes) == 0 { @@ -91,10 +96,11 @@ func (self authManager) healthCheck(authInfo api.AuthInfo) error { // NewAuthManager creates auth manager. func NewAuthManager(clientManager clientapi.ClientManager, tokenManager authApi.TokenManager, - authenticationModes authApi.AuthenticationModes) authApi.AuthManager { + authenticationModes authApi.AuthenticationModes, authenticationSkippable bool) authApi.AuthManager { return &authManager{ - tokenManager: tokenManager, - clientManager: clientManager, - authenticationModes: authenticationModes, + tokenManager: tokenManager, + clientManager: clientManager, + authenticationModes: authenticationModes, + authenticationSkippable: authenticationSkippable, } } diff --git a/src/app/backend/dashboard.go b/src/app/backend/dashboard.go index cb9579214c8d..b734265d9fd5 100644 --- a/src/app/backend/dashboard.go +++ b/src/app/backend/dashboard.go @@ -195,7 +195,10 @@ func initAuthManager(clientManager clientapi.ClientManager) authApi.AuthManager authModes.Add(authApi.Token) } - return auth.NewAuthManager(clientManager, tokenManager, authModes) + // UI logic dictates this should be the inverse of the cli option + authenticationSkippable := !args.Holder.GetDisableSkipButton() + + return auth.NewAuthManager(clientManager, tokenManager, authModes, authenticationSkippable) } func initArgHolder() { From 0a77a461a781987b40aae617b232472df53e52de Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:03:26 +0200 Subject: [PATCH 03/10] Added skip button API check in frontend --- src/app/externs/backendapi.js | 7 +++++++ src/app/frontend/login/component.js | 14 +++++++++++++- src/app/frontend/login/module.js | 2 ++ src/app/frontend/login/stateconfig.js | 9 +++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/app/externs/backendapi.js b/src/app/externs/backendapi.js index 53b416a305ea..ff81761455d0 100644 --- a/src/app/externs/backendapi.js +++ b/src/app/externs/backendapi.js @@ -1545,6 +1545,13 @@ backendApi.LoginModesResponse; */ backendApi.SupportedAuthenticationModes; +/** + * @typedef {{ + * skippable: boolean, + * }} + */ +backendApi.LoginSkippableResponse; + /** * @typedef {{ * running: number, diff --git a/src/app/frontend/login/component.js b/src/app/frontend/login/component.js index 7dcd8dd79b23..da13e947bdce 100644 --- a/src/app/frontend/login/component.js +++ b/src/app/frontend/login/component.js @@ -38,7 +38,7 @@ class LoginController { * @param {!../common/errorhandling/service.ErrorService} kdErrorService * @ngInject */ - constructor(kdNavService, kdAuthService, $state, kdAuthenticationModesResource, kdErrorService) { + constructor(kdNavService, kdAuthService, $state, kdAuthenticationModesResource, kdErrorService, kdSkipButtonEnabled) { /** @private {!./../chrome/nav/nav_service.NavService} */ this.kdNavService_ = kdNavService; /** @private {!./../common/auth/service.AuthService} */ @@ -62,6 +62,8 @@ class LoginController { this.supportedAuthenticationModes = Modes; /** @private {!../common/errorhandling/service.ErrorService} */ this.errorService_ = kdErrorService; + /** @private {!angular.$q.Promise} */ + this.skipButtonEnabledResource_ = kdSkipButtonEnabled; } /** @export */ @@ -81,6 +83,9 @@ class LoginController { this.authenticationModesResource_.then((authModes) => { this.enabledAuthenticationModes_ = authModes.modes; }); + this.skipButtonEnabledResource_.then((skippable) => { + this.skipButtonEnabled_ = skippable.skippable; + }); } /** @@ -100,6 +105,13 @@ class LoginController { return enabled; } + /** + * @export + */ + isSkipButtonEnabled() { + return this.skipButtonEnabled_; + } + /** * @param {!backendApi.LoginSpec} loginSpec * @export diff --git a/src/app/frontend/login/module.js b/src/app/frontend/login/module.js index 55b1bac00945..7411edcd8fc7 100644 --- a/src/app/frontend/login/module.js +++ b/src/app/frontend/login/module.js @@ -21,6 +21,7 @@ import {kubeConfigLoginComponent} from './kubeconfig_component'; import {loginOptionsComponent} from './options_component'; import stateConfig from './stateconfig'; import {authenticationModesResource} from './stateconfig'; +import {skippableResource} from './stateconfig'; import {tokenLoginComponent} from './token_component'; /** @@ -42,4 +43,5 @@ export default angular .component('kdTokenLogin', tokenLoginComponent) .component('kdKubeConfigLogin', kubeConfigLoginComponent) .factory('kdAuthenticationModesResource', authenticationModesResource) + .factory('kdSkipButtonEnabled', skippableResource) .config(stateConfig); diff --git a/src/app/frontend/login/stateconfig.js b/src/app/frontend/login/stateconfig.js index d31bb2ed1c76..4426dc4f7710 100644 --- a/src/app/frontend/login/stateconfig.js +++ b/src/app/frontend/login/stateconfig.js @@ -58,3 +58,12 @@ const config = { export function authenticationModesResource($resource) { return $resource('api/v1/login/modes').get().$promise; } + +/** + * @param {!angular.$resource} $resource + * @return {!angular.$q.Promise} + * @ngInject + */ +export function skippableResource($resource) { + return $resource('api/v1/login/skippable').get().$promise; +} From 82dfb3d2d6f1398e027c9ca213099eb6eeed43d7 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:03:57 +0200 Subject: [PATCH 04/10] Conditionally enable skip button --- src/app/frontend/login/login.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/frontend/login/login.html b/src/app/frontend/login/login.html index 50bf87d0bdf5..b5bf9a2509a4 100644 --- a/src/app/frontend/login/login.html +++ b/src/app/frontend/login/login.html @@ -45,7 +45,8 @@ [[Sign in|Text shown on the sign in button on login page]] + ng-click="$ctrl.skip()" + ng-if="$ctrl.isSkipButtonEnabled()"> [[Skip|Text shown on skip button on login page]] From de95268b513ece88d80864effb465736cb4c4589 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:07:02 +0200 Subject: [PATCH 05/10] Added missing argument to test cases --- src/app/backend/auth/manager_test.go | 4 ++-- src/app/backend/handler/apihandler_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/backend/auth/manager_test.go b/src/app/backend/auth/manager_test.go index 43ec80015b8d..4300b44f096b 100644 --- a/src/app/backend/auth/manager_test.go +++ b/src/app/backend/auth/manager_test.go @@ -139,7 +139,7 @@ func TestAuthManager_Login(t *testing.T) { } for _, c := range cases { - authManager := NewAuthManager(c.cManager, c.tManager, authApi.AuthenticationModes{authApi.Token: true}) + authManager := NewAuthManager(c.cManager, c.tManager, authApi.AuthenticationModes{authApi.Token: true}, true) response, err := authManager.Login(c.spec) if !areErrorsEqual(err, c.expectedErr) { @@ -166,7 +166,7 @@ func TestAuthManager_AuthenticationModes(t *testing.T) { } for _, c := range cases { - authManager := NewAuthManager(cManager, tManager, c.modes) + authManager := NewAuthManager(cManager, tManager, c.modes, true) got := authManager.AuthenticationModes() if !reflect.DeepEqual(got, c.expected) { diff --git a/src/app/backend/handler/apihandler_test.go b/src/app/backend/handler/apihandler_test.go index d3086e6bb4b1..9a427075bfe7 100644 --- a/src/app/backend/handler/apihandler_test.go +++ b/src/app/backend/handler/apihandler_test.go @@ -42,7 +42,7 @@ func getTokenManager() authApi.TokenManager { func TestCreateHTTPAPIHandler(t *testing.T) { cManager := client.NewClientManager("", "http://localhost:8080") - authManager := auth.NewAuthManager(cManager, getTokenManager(), authApi.AuthenticationModes{}) + authManager := auth.NewAuthManager(cManager, getTokenManager(), authApi.AuthenticationModes{}, true) sManager := settings.NewSettingsManager(cManager) sbManager := systembanner.NewSystemBannerManager("Hello world!", "INFO") _, err := CreateHTTPAPIHandler(nil, cManager, authManager, sManager, sbManager) From 4208c0dcc347acb0116eb618ce57f6c1309ca9ae Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:15:05 +0200 Subject: [PATCH 06/10] Added simple test case for skip button arg --- src/app/backend/auth/manager_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/app/backend/auth/manager_test.go b/src/app/backend/auth/manager_test.go index 4300b44f096b..5671e7b3dd41 100644 --- a/src/app/backend/auth/manager_test.go +++ b/src/app/backend/auth/manager_test.go @@ -174,3 +174,17 @@ func TestAuthManager_AuthenticationModes(t *testing.T) { } } } + +func TestAuthManager_AuthenticationSkippable(t *testing.T) { + cManager := &fakeClientManager{} + tManager := &fakeTokenManager{} + cModes := authApi.AuthenticationModes{} + + for _, flag := range []bool{true,false} { + authManager := NewAuthManager(cManager, tManager, cModes, flag) + got := authManager.AuthenticationSkippable() + if (got != flag) { + t.Errorf("Expected %v, but got %v.", flag, got) + } + } +} From b90c2aaeb43f17f7632c5c054fc482ae6ba76580 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:45:56 +0200 Subject: [PATCH 07/10] Declare undefined JS field --- src/app/frontend/login/component.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/frontend/login/component.js b/src/app/frontend/login/component.js index da13e947bdce..3f5073d33d3e 100644 --- a/src/app/frontend/login/component.js +++ b/src/app/frontend/login/component.js @@ -64,6 +64,8 @@ class LoginController { this.errorService_ = kdErrorService; /** @private {!angular.$q.Promise} */ this.skipButtonEnabledResource_ = kdSkipButtonEnabled; + /** @private {boolean} */ + this.skipButtonEnabled_; } /** @export */ From 68542afee6eab8c897db639d04976557501860c9 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 14:48:41 +0200 Subject: [PATCH 08/10] Fix indentation --- src/app/frontend/login/component.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/frontend/login/component.js b/src/app/frontend/login/component.js index 3f5073d33d3e..e67154bb87f9 100644 --- a/src/app/frontend/login/component.js +++ b/src/app/frontend/login/component.js @@ -38,7 +38,9 @@ class LoginController { * @param {!../common/errorhandling/service.ErrorService} kdErrorService * @ngInject */ - constructor(kdNavService, kdAuthService, $state, kdAuthenticationModesResource, kdErrorService, kdSkipButtonEnabled) { + constructor( + kdNavService, kdAuthService, $state, kdAuthenticationModesResource, kdErrorService, + kdSkipButtonEnabled) { /** @private {!./../chrome/nav/nav_service.NavService} */ this.kdNavService_ = kdNavService; /** @private {!./../common/auth/service.AuthService} */ From bc80c7673e917327f98b00b22878e8beeec98c68 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 15:39:43 +0200 Subject: [PATCH 09/10] Added missing parameter doc --- src/app/frontend/login/component.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/frontend/login/component.js b/src/app/frontend/login/component.js index e67154bb87f9..5f957e5cae7c 100644 --- a/src/app/frontend/login/component.js +++ b/src/app/frontend/login/component.js @@ -36,6 +36,7 @@ class LoginController { * @param {!ui.router.$state} $state * @param {!angular.$q.Promise} kdAuthenticationModesResource * @param {!../common/errorhandling/service.ErrorService} kdErrorService + * @param {!angular.$q.Promise} kdSkipButtonEnabled * @ngInject */ constructor( From 18510919241ef8baf0e80e59812fab38cdc65e08 Mon Sep 17 00:00:00 2001 From: Gregor Riepl Date: Mon, 4 Jun 2018 15:40:01 +0200 Subject: [PATCH 10/10] Added missing API call to test case --- src/test/frontend/login/component_test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/frontend/login/component_test.js b/src/test/frontend/login/component_test.js index 97390f576d85..c3c290f5cd1e 100644 --- a/src/test/frontend/login/component_test.js +++ b/src/test/frontend/login/component_test.js @@ -33,6 +33,8 @@ describe('Login component', () => { let authModesResource; /** @type {!angular.$q.Deferred} */ let deferred; + /** @type {!angular.$q.Promise} */ + let skipButtonEnabledResource; beforeEach(() => { angular.mock.module(errorModule.name); @@ -43,6 +45,7 @@ describe('Login component', () => { q = $q; deferred = q.defer(); authModesResource = deferred.promise; + skipButtonEnabledResource = deferred.promise; state = $state; authService = kdAuthService; scope = $rootScope; @@ -50,6 +53,7 @@ describe('Login component', () => { $state: $state, kdAuthService: authService, kdAuthenticationModesResource: authModesResource, + kdSkipButtonEnabled: skipButtonEnabledResource, }); });