From b02749f8777c0b5b49abb60ab49e75b6572e2610 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Tue, 9 Jun 2020 12:55:36 +0300 Subject: [PATCH] feat(auth): add custom user timeout (#3871) * feat(auth): introduce new timeout constant * feat(auth): pass timeout from handler * feat(auth): add timeout selector to auth settings view * feat(settings): add user session timeout property * feat(auth): load user session timeout from settings * fix(settings): use correct time format * feat(auth): remove no-auth flag * refactor(auth): move timeout mgmt to jwt service * refactor(client): remove no-auth checks from client * refactor(cli): remove defaultNoAuth * feat(settings): create settings with default user timeout value * refactor(db): save user session timeout always * refactor(jwt): return error * feat(auth): set session timeout in jwt service on update * feat(auth): add description and time settings * feat(auth): parse duration * feat(settings): validate user timeout format * refactor(settings): remove unneccesary import --- api/bolt/init.go | 1 + api/bolt/migrator/migrate_dbversion23.go | 6 +- api/cli/cli.go | 11 +--- api/cli/defaults.go | 1 - api/cli/defaults_windows.go | 1 - api/cmd/portainer/main.go | 35 +++++----- api/http/handler/auth/authenticate.go | 4 -- api/http/handler/auth/handler.go | 12 +--- api/http/handler/settings/handler.go | 5 +- api/http/handler/settings/settings_update.go | 17 +++++ api/http/security/bouncer.go | 64 ++++++++----------- api/http/server.go | 10 +-- api/jwt/jwt.go | 19 +++++- api/portainer.go | 10 +-- .../configs-datatable/configsDatatable.html | 4 +- .../configs-datatable/configsDatatable.js | 1 - .../containersDatatable.html | 4 +- .../containersDatatable.js | 1 - .../networkRowContent.html | 2 +- .../networks-datatable/networksDatatable.html | 2 +- .../networks-datatable/networksDatatable.js | 1 - .../secrets-datatable/secretsDatatable.html | 4 +- .../secrets-datatable/secretsDatatable.js | 1 - .../services-datatable/servicesDatatable.html | 4 +- .../services-datatable/servicesDatatable.js | 1 - .../volumes-datatable/volumesDatatable.html | 4 +- .../volumes-datatable/volumesDatatable.js | 1 - .../networkMacvlanForm.html | 2 +- .../networkMacvlanFormController.js | 7 +- app/docker/views/configs/configs.html | 1 - .../views/configs/create/createconfig.html | 2 +- app/docker/views/configs/edit/config.html | 3 +- app/docker/views/containers/containers.html | 1 - .../containers/create/createcontainer.html | 6 +- .../views/containers/edit/container.html | 8 +-- .../views/networks/create/createnetwork.html | 2 +- app/docker/views/networks/edit/network.html | 2 +- app/docker/views/networks/networks.html | 1 - .../views/secrets/create/createsecret.html | 2 +- app/docker/views/secrets/edit/secret.html | 3 +- app/docker/views/secrets/secrets.html | 1 - .../views/services/create/createservice.html | 2 +- app/docker/views/services/edit/service.html | 9 +-- app/docker/views/services/services.html | 1 - app/docker/views/swarm/swarm.html | 2 +- app/docker/views/swarm/swarmController.js | 4 +- .../views/volumes/create/createvolume.html | 10 +-- app/docker/views/volumes/edit/volume.html | 3 +- app/docker/views/volumes/volumes.html | 1 - .../registryRepositoriesController.js | 5 +- app/portainer/__module.js | 4 +- .../endpointsDatatable.html | 2 +- .../endpoints-datatable/endpointsDatatable.js | 1 - .../groups-datatable/groupsDatatable.html | 2 +- .../groups-datatable/groupsDatatable.js | 1 - .../stacks-datatable/stacksDatatable.html | 4 +- .../stacks-datatable/stacksDatatable.js | 1 - app/portainer/models/settings.js | 1 + app/portainer/services/stateManager.js | 1 - app/portainer/views/auth/authController.js | 13 ++-- app/portainer/views/endpoints/endpoints.html | 1 - app/portainer/views/groups/groups.html | 10 +-- app/portainer/views/home/home.html | 2 +- .../views/registries/registries.html | 4 +- .../views/registries/registriesController.js | 5 +- .../settingsAuthentication.html | 22 +++++++ .../settingsAuthenticationController.js | 23 +++++++ app/portainer/views/sidebar/sidebar.html | 15 ++--- .../views/sidebar/sidebarController.js | 23 +++---- .../views/stacks/create/createstack.html | 2 +- app/portainer/views/stacks/edit/stack.html | 4 +- app/portainer/views/stacks/stacks.html | 1 - app/portainer/views/templates/templates.html | 4 +- 73 files changed, 214 insertions(+), 236 deletions(-) diff --git a/api/bolt/init.go b/api/bolt/init.go index cc0a0f261..53fb28044 100644 --- a/api/bolt/init.go +++ b/api/bolt/init.go @@ -27,6 +27,7 @@ func (store *Store) Init() error { EnableHostManagementFeatures: false, EdgeAgentCheckinInterval: portainer.DefaultEdgeAgentCheckinIntervalInSeconds, TemplatesURL: portainer.DefaultTemplatesURL, + UserSessionTimeout: portainer.DefaultUserSessionTimeout, } err = store.SettingsService.UpdateSettings(defaultSettings) diff --git a/api/bolt/migrator/migrate_dbversion23.go b/api/bolt/migrator/migrate_dbversion23.go index 2688eecd5..fe4deca48 100644 --- a/api/bolt/migrator/migrate_dbversion23.go +++ b/api/bolt/migrator/migrate_dbversion23.go @@ -10,9 +10,9 @@ func (m *Migrator) updateSettingsToDB24() error { if legacySettings.TemplatesURL == "" { legacySettings.TemplatesURL = portainer.DefaultTemplatesURL - - return m.settingsService.UpdateSettings(legacySettings) } - return nil + legacySettings.UserSessionTimeout = portainer.DefaultUserSessionTimeout + + return m.settingsService.UpdateSettings(legacySettings) } diff --git a/api/cli/cli.go b/api/cli/cli.go index 914f01cb4..13e20e94b 100644 --- a/api/cli/cli.go +++ b/api/cli/cli.go @@ -1,7 +1,6 @@ package cli import ( - "log" "time" "github.com/portainer/portainer/api" @@ -20,7 +19,6 @@ const ( errInvalidEndpointProtocol = portainer.Error("Invalid endpoint protocol: Portainer only supports unix://, npipe:// or tcp://") errSocketOrNamedPipeNotFound = portainer.Error("Unable to locate Unix socket or named pipe") errInvalidSnapshotInterval = portainer.Error("Invalid snapshot interval") - errNoAuthExcludeAdminPassword = portainer.Error("Cannot use --no-auth with --admin-password or --admin-password-file") errAdminPassExcludeAdminPassFile = portainer.Error("Cannot use --admin-password with --admin-password-file") ) @@ -35,7 +33,6 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) { Assets: kingpin.Flag("assets", "Path to the assets").Default(defaultAssetsDirectory).Short('a').String(), Data: kingpin.Flag("data", "Path to the folder where the data is stored").Default(defaultDataDirectory).Short('d').String(), EndpointURL: kingpin.Flag("host", "Endpoint URL").Short('H').String(), - NoAuth: kingpin.Flag("no-auth", "Disable authentication (deprecated)").Default(defaultNoAuth).Bool(), NoAnalytics: kingpin.Flag("no-analytics", "Disable Analytics in app").Default(defaultNoAnalytics).Bool(), TLS: kingpin.Flag("tlsverify", "TLS support").Default(defaultTLS).Bool(), TLSSkipVerify: kingpin.Flag("tlsskipverify", "Disable TLS server verification").Default(defaultTLSSkipVerify).Bool(), @@ -81,10 +78,6 @@ func (*Service) ValidateFlags(flags *portainer.CLIFlags) error { return err } - if *flags.NoAuth && (*flags.AdminPassword != "" || *flags.AdminPasswordFile != "") { - return errNoAuthExcludeAdminPassword - } - if *flags.AdminPassword != "" && *flags.AdminPasswordFile != "" { return errAdminPassExcludeAdminPassFile } @@ -93,9 +86,7 @@ func (*Service) ValidateFlags(flags *portainer.CLIFlags) error { } func displayDeprecationWarnings(flags *portainer.CLIFlags) { - if *flags.NoAuth { - log.Println("Warning: the --no-auth flag is deprecated and will likely be removed in a future version of Portainer.") - } + } func validateEndpointURL(endpointURL string) error { diff --git a/api/cli/defaults.go b/api/cli/defaults.go index b79cddc5a..47e88755f 100644 --- a/api/cli/defaults.go +++ b/api/cli/defaults.go @@ -8,7 +8,6 @@ const ( defaultTunnelServerPort = "8000" defaultDataDirectory = "/data" defaultAssetsDirectory = "./" - defaultNoAuth = "false" defaultNoAnalytics = "false" defaultTLS = "false" defaultTLSSkipVerify = "false" diff --git a/api/cli/defaults_windows.go b/api/cli/defaults_windows.go index 2d1f2b2ab..bf42086ff 100644 --- a/api/cli/defaults_windows.go +++ b/api/cli/defaults_windows.go @@ -6,7 +6,6 @@ const ( defaultTunnelServerPort = "8000" defaultDataDirectory = "C:\\data" defaultAssetsDirectory = "./" - defaultNoAuth = "false" defaultNoAnalytics = "false" defaultTLS = "false" defaultTLSSkipVerify = "false" diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 34eed9cef..0598b0c6a 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -77,15 +77,17 @@ func initSwarmStackManager(assetsPath string, dataStorePath string, signatureSer return exec.NewSwarmStackManager(assetsPath, dataStorePath, signatureService, fileService, reverseTunnelService) } -func initJWTService(authenticationEnabled bool) portainer.JWTService { - if authenticationEnabled { - jwtService, err := jwt.NewService() - if err != nil { - log.Fatal(err) - } - return jwtService +func initJWTService(dataStore portainer.DataStore) (portainer.JWTService, error) { + settings, err := dataStore.Settings().Settings() + if err != nil { + return nil, err } - return nil + + jwtService, err := jwt.NewService(settings.UserSessionTimeout) + if err != nil { + return nil, err + } + return jwtService, nil } func initDigitalSignatureService() portainer.DigitalSignatureService { @@ -188,9 +190,8 @@ func loadSchedulesFromDatabase(jobScheduler portainer.JobScheduler, jobService p func initStatus(flags *portainer.CLIFlags) *portainer.Status { return &portainer.Status{ - Analytics: !*flags.NoAnalytics, - Authentication: !*flags.NoAuth, - Version: portainer.APIVersion, + Analytics: !*flags.NoAnalytics, + Version: portainer.APIVersion, } } @@ -392,7 +393,10 @@ func main() { dataStore := initDataStore(*flags.Data, fileService) defer dataStore.Close() - jwtService := initJWTService(!*flags.NoAuth) + jwtService, err := initJWTService(dataStore) + if err != nil { + log.Fatal(err) + } ldapService := initLDAPService() @@ -402,7 +406,7 @@ func main() { digitalSignatureService := initDigitalSignatureService() - err := initKeyPair(fileService, digitalSignatureService) + err = initKeyPair(fileService, digitalSignatureService) if err != nil { log.Fatal(err) } @@ -492,9 +496,7 @@ func main() { } } - if !*flags.NoAuth { - go terminateIfNoAdminCreated(dataStore) - } + go terminateIfNoAdminCreated(dataStore) err = reverseTunnelService.StartTunnelServer(*flags.TunnelAddr, *flags.TunnelPort, snapshotter) if err != nil { @@ -506,7 +508,6 @@ func main() { Status: applicationStatus, BindAddress: *flags.Addr, AssetsPath: *flags.Assets, - AuthDisabled: *flags.NoAuth, DataStore: dataStore, SwarmStackManager: swarmStackManager, ComposeStackManager: composeStackManager, diff --git a/api/http/handler/auth/authenticate.go b/api/http/handler/auth/authenticate.go index 1db970bb3..6a1d47308 100644 --- a/api/http/handler/auth/authenticate.go +++ b/api/http/handler/auth/authenticate.go @@ -32,10 +32,6 @@ func (payload *authenticatePayload) Validate(r *http.Request) error { } func (handler *Handler) authenticate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { - if handler.authDisabled { - return &httperror.HandlerError{http.StatusServiceUnavailable, "Cannot authenticate user. Portainer was started with the --no-auth flag", ErrAuthDisabled} - } - var payload authenticatePayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { diff --git a/api/http/handler/auth/handler.go b/api/http/handler/auth/handler.go index 345884980..bfb33c6f9 100644 --- a/api/http/handler/auth/handler.go +++ b/api/http/handler/auth/handler.go @@ -10,16 +10,9 @@ import ( "github.com/portainer/portainer/api/http/security" ) -const ( - // ErrAuthDisabled is an error raised when trying to access the authentication endpoints - // when the server has been started with the --no-auth flag - ErrAuthDisabled = portainer.Error("Authentication is disabled") -) - // Handler is the HTTP handler used to handle authentication operations. type Handler struct { *mux.Router - authDisabled bool DataStore portainer.DataStore CryptoService portainer.CryptoService JWTService portainer.JWTService @@ -29,10 +22,9 @@ type Handler struct { } // NewHandler creates a handler to manage authentication operations. -func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter, authDisabled bool) *Handler { +func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter) *Handler { h := &Handler{ - Router: mux.NewRouter(), - authDisabled: authDisabled, + Router: mux.NewRouter(), } h.Handle("/auth/oauth/validate", diff --git a/api/http/handler/settings/handler.go b/api/http/handler/settings/handler.go index 349d05228..9bbe1cf52 100644 --- a/api/http/handler/settings/handler.go +++ b/api/http/handler/settings/handler.go @@ -17,11 +17,12 @@ func hideFields(settings *portainer.Settings) { // Handler is the HTTP handler used to handle settings operations. type Handler struct { *mux.Router + AuthorizationService *portainer.AuthorizationService DataStore portainer.DataStore - LDAPService portainer.LDAPService FileService portainer.FileService JobScheduler portainer.JobScheduler - AuthorizationService *portainer.AuthorizationService + JWTService portainer.JWTService + LDAPService portainer.LDAPService } // NewHandler creates a handler to manage settings operations. diff --git a/api/http/handler/settings/settings_update.go b/api/http/handler/settings/settings_update.go index 86d26bdaa..81c1aa249 100644 --- a/api/http/handler/settings/settings_update.go +++ b/api/http/handler/settings/settings_update.go @@ -2,6 +2,7 @@ package settings import ( "net/http" + "time" "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" @@ -25,6 +26,7 @@ type settingsUpdatePayload struct { TemplatesURL *string EdgeAgentCheckinInterval *int EnableEdgeComputeFeatures *bool + UserSessionTimeout *string } func (payload *settingsUpdatePayload) Validate(r *http.Request) error { @@ -37,6 +39,13 @@ func (payload *settingsUpdatePayload) Validate(r *http.Request) error { if payload.TemplatesURL != nil && *payload.TemplatesURL != "" && !govalidator.IsURL(*payload.TemplatesURL) { return portainer.Error("Invalid external templates URL. Must correspond to a valid URL format") } + if payload.UserSessionTimeout != nil { + _, err := time.ParseDuration(*payload.UserSessionTimeout) + if err != nil { + return portainer.Error("Invalid user session timeout") + } + } + return nil } @@ -125,6 +134,14 @@ func (handler *Handler) settingsUpdate(w http.ResponseWriter, r *http.Request) * settings.EdgeAgentCheckinInterval = *payload.EdgeAgentCheckinInterval } + if payload.UserSessionTimeout != nil { + settings.UserSessionTimeout = *payload.UserSessionTimeout + + userSessionDuration, _ := time.ParseDuration(*payload.UserSessionTimeout) + + handler.JWTService.SetUserSessionDuration(userSessionDuration) + } + tlsError := handler.updateTLS(settings) if tlsError != nil { return tlsError diff --git a/api/http/security/bouncer.go b/api/http/security/bouncer.go index d6ded7f62..3fc61656a 100644 --- a/api/http/security/bouncer.go +++ b/api/http/security/bouncer.go @@ -16,7 +16,6 @@ type ( dataStore portainer.DataStore jwtService portainer.JWTService rbacExtensionClient *rbacExtensionClient - authDisabled bool } // RestrictedRequestContext is a data structure containing information @@ -30,12 +29,11 @@ type ( ) // NewRequestBouncer initializes a new RequestBouncer -func NewRequestBouncer(dataStore portainer.DataStore, jwtService portainer.JWTService, authenticationDisabled bool, rbacExtensionURL string) *RequestBouncer { +func NewRequestBouncer(dataStore portainer.DataStore, jwtService portainer.JWTService, rbacExtensionURL string) *RequestBouncer { return &RequestBouncer{ dataStore: dataStore, jwtService: jwtService, rbacExtensionClient: newRBACExtensionClient(rbacExtensionURL), - authDisabled: authenticationDisabled, } } @@ -289,44 +287,38 @@ func (bouncer *RequestBouncer) mwUpgradeToRestrictedRequest(next http.Handler) h func (bouncer *RequestBouncer) mwCheckAuthentication(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var tokenData *portainer.TokenData - if !bouncer.authDisabled { - var token string + var token string - // Optionally, token might be set via the "token" query parameter. - // For example, in websocket requests - token = r.URL.Query().Get("token") + // Optionally, token might be set via the "token" query parameter. + // For example, in websocket requests + token = r.URL.Query().Get("token") - // Get token from the Authorization header - tokens, ok := r.Header["Authorization"] - if ok && len(tokens) >= 1 { - token = tokens[0] - token = strings.TrimPrefix(token, "Bearer ") - } + // Get token from the Authorization header + tokens, ok := r.Header["Authorization"] + if ok && len(tokens) >= 1 { + token = tokens[0] + token = strings.TrimPrefix(token, "Bearer ") + } - if token == "" { - httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized) - return - } + if token == "" { + httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized) + return + } - var err error - tokenData, err = bouncer.jwtService.ParseAndVerifyToken(token) - if err != nil { - httperror.WriteError(w, http.StatusUnauthorized, "Invalid JWT token", err) - return - } + var err error + tokenData, err = bouncer.jwtService.ParseAndVerifyToken(token) + if err != nil { + httperror.WriteError(w, http.StatusUnauthorized, "Invalid JWT token", err) + return + } - _, err = bouncer.dataStore.User().User(tokenData.ID) - if err != nil && err == portainer.ErrObjectNotFound { - httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized) - return - } else if err != nil { - httperror.WriteError(w, http.StatusInternalServerError, "Unable to retrieve user details from the database", err) - return - } - } else { - tokenData = &portainer.TokenData{ - Role: portainer.AdministratorRole, - } + _, err = bouncer.dataStore.User().User(tokenData.ID) + if err != nil && err == portainer.ErrObjectNotFound { + httperror.WriteError(w, http.StatusUnauthorized, "Unauthorized", portainer.ErrUnauthorized) + return + } else if err != nil { + httperror.WriteError(w, http.StatusInternalServerError, "Unable to retrieve user details from the database", err) + return } ctx := storeTokenData(r, tokenData) diff --git a/api/http/server.go b/api/http/server.go index 40e2a880f..1834c4100 100644 --- a/api/http/server.go +++ b/api/http/server.go @@ -47,7 +47,6 @@ import ( type Server struct { BindAddress string AssetsPath string - AuthDisabled bool Status *portainer.Status ReverseTunnelService portainer.ReverseTunnelService ExtensionManager portainer.ExtensionManager @@ -77,11 +76,11 @@ func (server *Server) Start() error { authorizationService := portainer.NewAuthorizationService(server.DataStore) rbacExtensionURL := proxyManager.GetExtensionURL(portainer.RBACExtension) - requestBouncer := security.NewRequestBouncer(server.DataStore, server.JWTService, server.AuthDisabled, rbacExtensionURL) + requestBouncer := security.NewRequestBouncer(server.DataStore, server.JWTService, rbacExtensionURL) rateLimiter := security.NewRateLimiter(10, 1*time.Second, 1*time.Hour) - var authHandler = auth.NewHandler(requestBouncer, rateLimiter, server.AuthDisabled) + var authHandler = auth.NewHandler(requestBouncer, rateLimiter) authHandler.DataStore = server.DataStore authHandler.CryptoService = server.CryptoService authHandler.JWTService = server.JWTService @@ -153,11 +152,12 @@ func (server *Server) Start() error { schedulesHandler.ReverseTunnelService = server.ReverseTunnelService var settingsHandler = settings.NewHandler(requestBouncer) + settingsHandler.AuthorizationService = authorizationService settingsHandler.DataStore = server.DataStore - settingsHandler.LDAPService = server.LDAPService settingsHandler.FileService = server.FileService settingsHandler.JobScheduler = server.JobScheduler - settingsHandler.AuthorizationService = authorizationService + settingsHandler.JWTService = server.JWTService + settingsHandler.LDAPService = server.LDAPService var stackHandler = stacks.NewHandler(requestBouncer) stackHandler.DataStore = server.DataStore diff --git a/api/jwt/jwt.go b/api/jwt/jwt.go index 316495724..aedb264de 100644 --- a/api/jwt/jwt.go +++ b/api/jwt/jwt.go @@ -12,7 +12,8 @@ import ( // Service represents a service for managing JWT tokens. type Service struct { - secret []byte + secret []byte + userSessionTimeout time.Duration } type claims struct { @@ -23,20 +24,27 @@ type claims struct { } // NewService initializes a new service. It will generate a random key that will be used to sign JWT tokens. -func NewService() (*Service, error) { +func NewService(userSessionDuration string) (*Service, error) { + userSessionTimeout, err := time.ParseDuration(userSessionDuration) + if err != nil { + return nil, err + } + secret := securecookie.GenerateRandomKey(32) if secret == nil { return nil, portainer.ErrSecretGeneration } + service := &Service{ secret, + userSessionTimeout, } return service, nil } // GenerateToken generates a new JWT token. func (service *Service) GenerateToken(data *portainer.TokenData) (string, error) { - expireToken := time.Now().Add(time.Hour * 8).Unix() + expireToken := time.Now().Add(service.userSessionTimeout).Unix() cl := claims{ UserID: int(data.ID), Username: data.Username, @@ -77,3 +85,8 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, return nil, portainer.ErrInvalidJWTToken } + +// SetUserSessionDuration sets the user session duration +func (service *Service) SetUserSessionDuration(userSessionDuration time.Duration) { + service.userSessionTimeout = userSessionDuration +} diff --git a/api/portainer.go b/api/portainer.go index a2ec3efd6..0f3b3fed0 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -46,7 +46,6 @@ type ( EndpointURL *string Labels *[]Pair Logo *string - NoAuth *bool NoAnalytics *bool Templates *string TLS *bool @@ -459,6 +458,7 @@ type ( EnableHostManagementFeatures bool `json:"EnableHostManagementFeatures"` EdgeAgentCheckinInterval int `json:"EdgeAgentCheckinInterval"` EnableEdgeComputeFeatures bool `json:"EnableEdgeComputeFeatures"` + UserSessionTimeout string `json:"UserSessionTimeout"` // Deprecated fields DisplayDonationHeader bool @@ -517,9 +517,8 @@ type ( // Status represents the application status Status struct { - Authentication bool `json:"Authentication"` - Analytics bool `json:"Analytics"` - Version string `json:"Version"` + Analytics bool `json:"Analytics"` + Version string `json:"Version"` } // Tag represents a tag that can be associated to a resource @@ -842,6 +841,7 @@ type ( JWTService interface { GenerateToken(data *TokenData) (string, error) ParseAndVerifyToken(token string) (*TokenData, error) + SetUserSessionDuration(userSessionDuration time.Duration) } // LDAPService represents a service used to authenticate users against a LDAP/AD @@ -1057,6 +1057,8 @@ const ( LocalExtensionManifestFile = "/extensions.json" // DefaultTemplatesURL represents the URL to the official templates supported by Portainer DefaultTemplatesURL = "https://raw.githubusercontent.com/portainer/templates/master/templates-2.0.json" + // DefaultUserSessionTimeout represents the default timeout after which the user session is cleared + DefaultUserSessionTimeout = "8h" ) const ( diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index a6b8aa6a7..8939b44be 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -90,7 +90,7 @@ - + Ownership @@ -112,7 +112,7 @@ {{ item.Name }} {{ item.CreatedAt | getisodate }} - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.js b/app/docker/components/datatables/configs-datatable/configsDatatable.js index 0e75d7013..569281fcc 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.js +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.docker').component('configsDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', removeAction: '<', refreshCallback: '<', }, diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index 44aa27c7e..819fc8c0b 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -246,7 +246,7 @@ - + Ownership @@ -319,7 +319,7 @@ - - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.js b/app/docker/components/datatables/containers-datatable/containersDatatable.js index e136cf191..0edc97de0 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.js +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.docker').component('containersDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', showHostColumn: '<', showAddAction: '<', offlineMode: '<', diff --git a/app/docker/components/datatables/networks-datatable/network-row-content/networkRowContent.html b/app/docker/components/datatables/networks-datatable/network-row-content/networkRowContent.html index 04fb4d94d..b2152f746 100644 --- a/app/docker/components/datatables/networks-datatable/network-row-content/networkRowContent.html +++ b/app/docker/components/datatables/networks-datatable/network-row-content/networkRowContent.html @@ -28,7 +28,7 @@ {{ item.IPAM.IPV6Configs[0].Subnet ? item.IPAM.IPV6Configs[0].Subnet : '-' }} {{ item.IPAM.IPV6Configs[0].Gateway ? item.IPAM.IPV6Configs[0].Gateway : '-' }} {{ item.NodeName ? item.NodeName : '-' }} - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/networks-datatable/networksDatatable.html b/app/docker/components/datatables/networks-datatable/networksDatatable.html index 0c8f1e905..bf54ca837 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatable.html +++ b/app/docker/components/datatables/networks-datatable/networksDatatable.html @@ -151,7 +151,7 @@ - + Ownership diff --git a/app/docker/components/datatables/networks-datatable/networksDatatable.js b/app/docker/components/datatables/networks-datatable/networksDatatable.js index a46961009..20d48108b 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatable.js +++ b/app/docker/components/datatables/networks-datatable/networksDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.docker').component('networksDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', showHostColumn: '<', removeAction: '<', offlineMode: '<', diff --git a/app/docker/components/datatables/secrets-datatable/secretsDatatable.html b/app/docker/components/datatables/secrets-datatable/secretsDatatable.html index e804e738a..f7d9b0c6e 100644 --- a/app/docker/components/datatables/secrets-datatable/secretsDatatable.html +++ b/app/docker/components/datatables/secrets-datatable/secretsDatatable.html @@ -90,7 +90,7 @@ - + Ownership @@ -112,7 +112,7 @@ {{ item.Name }} {{ item.CreatedAt | getisodate }} - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/secrets-datatable/secretsDatatable.js b/app/docker/components/datatables/secrets-datatable/secretsDatatable.js index c3f0c0ed7..840a98fc2 100644 --- a/app/docker/components/datatables/secrets-datatable/secretsDatatable.js +++ b/app/docker/components/datatables/secrets-datatable/secretsDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.docker').component('secretsDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', removeAction: '<', refreshCallback: '<', }, diff --git a/app/docker/components/datatables/services-datatable/servicesDatatable.html b/app/docker/components/datatables/services-datatable/servicesDatatable.html index c5fbc3dff..3e72d09f4 100644 --- a/app/docker/components/datatables/services-datatable/servicesDatatable.html +++ b/app/docker/components/datatables/services-datatable/servicesDatatable.html @@ -115,7 +115,7 @@ - + Ownership @@ -180,7 +180,7 @@ - {{ item.UpdatedAt | getisodate }} - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/services-datatable/servicesDatatable.js b/app/docker/components/datatables/services-datatable/servicesDatatable.js index 7f8731892..6e5bbfb77 100644 --- a/app/docker/components/datatables/services-datatable/servicesDatatable.js +++ b/app/docker/components/datatables/services-datatable/servicesDatatable.js @@ -10,7 +10,6 @@ angular.module('portainer.docker').component('servicesDatatable', { reverseOrder: '<', nodes: '<', agentProxy: '<', - showOwnershipColumn: '<', showUpdateAction: '<', showAddAction: '<', showStackColumn: '<', diff --git a/app/docker/components/datatables/volumes-datatable/volumesDatatable.html b/app/docker/components/datatables/volumes-datatable/volumesDatatable.html index 12a9c776f..573acd415 100644 --- a/app/docker/components/datatables/volumes-datatable/volumesDatatable.html +++ b/app/docker/components/datatables/volumes-datatable/volumesDatatable.html @@ -142,7 +142,7 @@ - + Ownership @@ -177,7 +177,7 @@ {{ item.Mountpoint | truncatelr }} {{ item.CreatedAt | getisodate }} {{ item.NodeName ? item.NodeName : '-' }} - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/docker/components/datatables/volumes-datatable/volumesDatatable.js b/app/docker/components/datatables/volumes-datatable/volumesDatatable.js index af00b13ce..0ee1524e3 100644 --- a/app/docker/components/datatables/volumes-datatable/volumesDatatable.js +++ b/app/docker/components/datatables/volumes-datatable/volumesDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.docker').component('volumesDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', showHostColumn: '<', removeAction: '<', showBrowseAction: '<', diff --git a/app/docker/components/network-macvlan-form/networkMacvlanForm.html b/app/docker/components/network-macvlan-form/networkMacvlanForm.html index fca929aa5..59898e2ee 100644 --- a/app/docker/components/network-macvlan-form/networkMacvlanForm.html +++ b/app/docker/components/network-macvlan-form/networkMacvlanForm.html @@ -74,7 +74,7 @@ state="$ctrl.data.DatatableState" order-by="Hostname" show-ip-address-column="$ctrl.applicationState.endpoint.apiVersion >= 1.25" - access-to-node-details="!$ctrl.applicationState.application.authentication || $ctrl.isAdmin" + access-to-node-details="$ctrl.isAdmin" name="node_selector" ng-model="tmp" ng-required="$ctrl.requiredNodeSelection()" diff --git a/app/docker/components/network-macvlan-form/networkMacvlanFormController.js b/app/docker/components/network-macvlan-form/networkMacvlanFormController.js index 8a6fa0084..e3873648a 100644 --- a/app/docker/components/network-macvlan-form/networkMacvlanFormController.js +++ b/app/docker/components/network-macvlan-form/networkMacvlanFormController.js @@ -23,10 +23,9 @@ angular.module('portainer.docker').controller('NetworkMacvlanFormController', [ }; function initComponent() { - if (StateManager.getState().application.authentication) { - var isAdmin = Authentication.isAdmin(); - ctrl.isAdmin = isAdmin; - } + var isAdmin = Authentication.isAdmin(); + ctrl.isAdmin = isAdmin; + var provider = ctrl.applicationState.endpoint.mode.provider; var apiVersion = ctrl.applicationState.endpoint.apiVersion; $q.all({ diff --git a/app/docker/views/configs/configs.html b/app/docker/views/configs/configs.html index 0145c737e..ec47421e7 100644 --- a/app/docker/views/configs/configs.html +++ b/app/docker/views/configs/configs.html @@ -15,7 +15,6 @@ dataset="ctrl.configs" table-key="configs" order-by="Name" - show-ownership-column="applicationState.application.authentication" remove-action="ctrl.removeAction" refresh-callback="ctrl.getConfigs" > diff --git a/app/docker/views/configs/create/createconfig.html b/app/docker/views/configs/create/createconfig.html index e92186639..06e0af527 100644 --- a/app/docker/views/configs/create/createconfig.html +++ b/app/docker/views/configs/create/createconfig.html @@ -57,7 +57,7 @@ - +
diff --git a/app/docker/views/configs/edit/config.html b/app/docker/views/configs/edit/config.html index d11a48616..591ae9b8a 100644 --- a/app/docker/views/configs/edit/config.html +++ b/app/docker/views/configs/edit/config.html @@ -59,8 +59,7 @@
- - +
diff --git a/app/docker/views/containers/containers.html b/app/docker/views/containers/containers.html index 98d246a89..b1ba1e791 100644 --- a/app/docker/views/containers/containers.html +++ b/app/docker/views/containers/containers.html @@ -15,7 +15,6 @@ dataset="containers" table-key="containers" order-by="Status" - show-ownership-column="applicationState.application.authentication" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-add-action="true" offline-mode="offlineMode" diff --git a/app/docker/views/containers/create/createcontainer.html b/app/docker/views/containers/create/createcontainer.html index f339a9090..e6d1ea848 100644 --- a/app/docker/views/containers/create/createcontainer.html +++ b/app/docker/views/containers/create/createcontainer.html @@ -126,11 +126,7 @@
- +
diff --git a/app/docker/views/containers/edit/container.html b/app/docker/views/containers/edit/container.html index b8e9ff0a2..41d8349f3 100644 --- a/app/docker/views/containers/edit/container.html +++ b/app/docker/views/containers/edit/container.html @@ -135,13 +135,7 @@
- - +
diff --git a/app/docker/views/networks/create/createnetwork.html b/app/docker/views/networks/create/createnetwork.html index 21877f025..7cfc402c8 100644 --- a/app/docker/views/networks/create/createnetwork.html +++ b/app/docker/views/networks/create/createnetwork.html @@ -194,7 +194,7 @@
- +
diff --git a/app/docker/views/networks/edit/network.html b/app/docker/views/networks/edit/network.html index 9adcba96b..bf4a04170 100644 --- a/app/docker/views/networks/edit/network.html +++ b/app/docker/views/networks/edit/network.html @@ -66,7 +66,7 @@ - +
diff --git a/app/docker/views/secrets/edit/secret.html b/app/docker/views/secrets/edit/secret.html index 6375294eb..daa5bc912 100644 --- a/app/docker/views/secrets/edit/secret.html +++ b/app/docker/views/secrets/edit/secret.html @@ -56,6 +56,5 @@
- - + diff --git a/app/docker/views/secrets/secrets.html b/app/docker/views/secrets/secrets.html index a6ddde5af..f668ec70e 100644 --- a/app/docker/views/secrets/secrets.html +++ b/app/docker/views/secrets/secrets.html @@ -15,7 +15,6 @@ dataset="secrets" table-key="secrets" order-by="Name" - show-ownership-column="applicationState.application.authentication" remove-action="removeAction" refresh-callback="getSecrets" > diff --git a/app/docker/views/services/create/createservice.html b/app/docker/views/services/create/createservice.html index 3494a88f0..639274cc8 100644 --- a/app/docker/views/services/create/createservice.html +++ b/app/docker/views/services/create/createservice.html @@ -112,7 +112,7 @@
- +
diff --git a/app/docker/views/services/edit/service.html b/app/docker/views/services/edit/service.html index 37579731a..82cc85bca 100644 --- a/app/docker/views/services/edit/service.html +++ b/app/docker/views/services/edit/service.html @@ -99,7 +99,6 @@

Note: you can only rollback one level of changes. Clicking the rollback button without making a new change will undo your previous rollback

- - +

diff --git a/app/docker/views/swarm/swarmController.js b/app/docker/views/swarm/swarmController.js index 9a5b4c08b..ff4f7c409 100644 --- a/app/docker/views/swarm/swarmController.js +++ b/app/docker/views/swarm/swarmController.js @@ -82,9 +82,7 @@ angular.module('portainer.docker').controller('SwarmController', [ } function initView() { - if (StateManager.getState().application.authentication) { - $scope.isAdmin = Authentication.isAdmin(); - } + $scope.isAdmin = Authentication.isAdmin(); var provider = $scope.applicationState.endpoint.mode.provider; $q.all({ diff --git a/app/docker/views/volumes/create/createvolume.html b/app/docker/views/volumes/create/createvolume.html index d3985b68c..2dc4ef6a4 100644 --- a/app/docker/views/volumes/create/createvolume.html +++ b/app/docker/views/volumes/create/createvolume.html @@ -72,9 +72,7 @@ -
- Ensure nfs-utils are installed on your hosts. -
+
Ensure nfs-utils are installed on your hosts.
@@ -87,9 +85,7 @@ -
- Ensure cifs-utils are installed on your hosts. -
+
Ensure cifs-utils are installed on your hosts.
@@ -110,7 +106,7 @@ - +
diff --git a/app/docker/views/volumes/edit/volume.html b/app/docker/views/volumes/edit/volume.html index 3d9fcf342..d55d317be 100644 --- a/app/docker/views/volumes/edit/volume.html +++ b/app/docker/views/volumes/edit/volume.html @@ -78,8 +78,7 @@
- - +
diff --git a/app/docker/views/volumes/volumes.html b/app/docker/views/volumes/volumes.html index c43c8a430..f3c860390 100644 --- a/app/docker/views/volumes/volumes.html +++ b/app/docker/views/volumes/volumes.html @@ -16,7 +16,6 @@ table-key="volumes" order-by="Id" remove-action="removeAction" - show-ownership-column="applicationState.application.authentication" show-host-column="applicationState.endpoint.mode.agentProxy && applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE'" show-browse-action="showBrowseAction" offline-mode="offlineMode" diff --git a/app/extensions/registry-management/views/repositories/registryRepositoriesController.js b/app/extensions/registry-management/views/repositories/registryRepositoriesController.js index 3dbbd7a2b..00ad8b0cb 100644 --- a/app/extensions/registry-management/views/repositories/registryRepositoriesController.js +++ b/app/extensions/registry-management/views/repositories/registryRepositoriesController.js @@ -42,10 +42,7 @@ angular.module('portainer.extensions.registrymanagement').controller('RegistryRe function initView() { const registryId = $transition$.params().id; - var authenticationEnabled = $scope.applicationState.application.authentication; - if (authenticationEnabled) { - $scope.isAdmin = Authentication.isAdmin(); - } + $scope.isAdmin = Authentication.isAdmin(); RegistryService.registry(registryId) .then(function success(data) { diff --git a/app/portainer/__module.js b/app/portainer/__module.js index 6d03c1d8f..7a7df77e9 100644 --- a/app/portainer/__module.js +++ b/app/portainer/__module.js @@ -55,9 +55,7 @@ angular.module('portainer.app', []).config([ if (state.application.analytics) { initAnalytics(Analytics, $rootScope); } - if (state.application.authentication) { - return $async(initAuthentication, authManager, Authentication, $rootScope, $state); - } + return $async(initAuthentication, authManager, Authentication, $rootScope, $state); }) .then(() => deferred.resolve()) .catch(function error(err) { diff --git a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html index e053c0adb..524cf1215 100644 --- a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html +++ b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html @@ -83,7 +83,7 @@ {{ item.URL | stripprotocol }} {{ item.GroupName }} - Manage access + Manage access diff --git a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.js b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.js index b717fe566..807f05192 100644 --- a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.js +++ b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.js @@ -7,7 +7,6 @@ angular.module('portainer.app').component('endpointsDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - accessManagement: '<', removeAction: '<', retrievePage: '<', }, diff --git a/app/portainer/components/datatables/groups-datatable/groupsDatatable.html b/app/portainer/components/datatables/groups-datatable/groupsDatatable.html index 47f424735..58ed43cc0 100644 --- a/app/portainer/components/datatables/groups-datatable/groupsDatatable.html +++ b/app/portainer/components/datatables/groups-datatable/groupsDatatable.html @@ -53,7 +53,7 @@ {{ item.Name }} - Manage access + Manage access diff --git a/app/portainer/components/datatables/groups-datatable/groupsDatatable.js b/app/portainer/components/datatables/groups-datatable/groupsDatatable.js index a71931360..f8e69b55a 100644 --- a/app/portainer/components/datatables/groups-datatable/groupsDatatable.js +++ b/app/portainer/components/datatables/groups-datatable/groupsDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.app').component('groupsDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - accessManagement: '<', removeAction: '<', }, }); diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html index a4010af61..073e3db2b 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html @@ -91,7 +91,7 @@ Control - + Ownership @@ -127,7 +127,7 @@ Total - + {{ item.ResourceControl.Ownership ? item.ResourceControl.Ownership : item.ResourceControl.Ownership = $ctrl.RCO.ADMINISTRATORS }} diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.js b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.js index 1e1e11c98..cdf581415 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.js +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.js @@ -8,7 +8,6 @@ angular.module('portainer.app').component('stacksDatatable', { tableKey: '@', orderBy: '@', reverseOrder: '<', - showOwnershipColumn: '<', removeAction: '<', offlineMode: '<', refreshCallback: '<', diff --git a/app/portainer/models/settings.js b/app/portainer/models/settings.js index 8e0247db9..f7498f81b 100644 --- a/app/portainer/models/settings.js +++ b/app/portainer/models/settings.js @@ -12,6 +12,7 @@ export function SettingsViewModel(data) { this.EnableHostManagementFeatures = data.EnableHostManagementFeatures; this.EdgeAgentCheckinInterval = data.EdgeAgentCheckinInterval; this.EnableEdgeComputeFeatures = data.EnableEdgeComputeFeatures; + this.UserSessionTimeout = data.UserSessionTimeout; } export function PublicSettingsViewModel(settings) { diff --git a/app/portainer/services/stateManager.js b/app/portainer/services/stateManager.js index fa2b1c72b..e46502334 100644 --- a/app/portainer/services/stateManager.js +++ b/app/portainer/services/stateManager.js @@ -77,7 +77,6 @@ angular.module('portainer.app').factory('StateManager', [ }; function assignStateFromStatusAndSettings(status, settings) { - state.application.authentication = status.Authentication; state.application.analytics = status.Analytics; state.application.version = status.Version; state.application.logo = settings.LogoURL; diff --git a/app/portainer/views/auth/authController.js b/app/portainer/views/auth/authController.js index 27384fe4c..a0eb03acc 100644 --- a/app/portainer/views/auth/authController.js +++ b/app/portainer/views/auth/authController.js @@ -128,10 +128,10 @@ class AuthenticationController { } } - async checkForEndpointsAsync(noAuth) { + async checkForEndpointsAsync() { try { const endpoints = await this.EndpointService.endpoints(0, 1); - const isAdmin = noAuth || this.Authentication.isAdmin(); + const isAdmin = this.Authentication.isAdmin(); if (endpoints.value.length === 0 && isAdmin) { return this.$state.go('portainer.init.endpoint'); @@ -162,7 +162,7 @@ class AuthenticationController { async postLoginSteps() { await this.retrieveAndSaveEnabledExtensionsAsync(); - await this.checkForEndpointsAsync(false); + await this.checkForEndpointsAsync(); await this.checkForLatestVersionAsync(); } /** @@ -282,12 +282,7 @@ class AuthenticationController { } this.state.loginInProgress = false; - const authenticationEnabled = this.$scope.applicationState.application.authentication; - if (!authenticationEnabled) { - await this.checkForEndpointsAsync(true); - } else { - await this.authEnabledFlowAsync(); - } + await this.authEnabledFlowAsync(); } catch (err) { this.Notifications.error('Failure', err, 'Unable to retrieve public settings'); } diff --git a/app/portainer/views/endpoints/endpoints.html b/app/portainer/views/endpoints/endpoints.html index 35f0190ff..7f1813ca7 100644 --- a/app/portainer/views/endpoints/endpoints.html +++ b/app/portainer/views/endpoints/endpoints.html @@ -14,7 +14,6 @@ title-icon="fa-plug" table-key="endpoints" order-by="Name" - access-management="applicationState.application.authentication" remove-action="removeAction" retrieve-page="getPaginatedEndpoints" > diff --git a/app/portainer/views/groups/groups.html b/app/portainer/views/groups/groups.html index 1899d9e18..42e491286 100644 --- a/app/portainer/views/groups/groups.html +++ b/app/portainer/views/groups/groups.html @@ -9,14 +9,6 @@
- +
diff --git a/app/portainer/views/home/home.html b/app/portainer/views/home/home.html index 669002a5e..489254d9b 100644 --- a/app/portainer/views/home/home.html +++ b/app/portainer/views/home/home.html @@ -37,7 +37,7 @@ table-key="home_endpoints" tags="tags" dashboard-action="goToDashboard" - show-snapshot-action="!applicationState.application.authentication || isAdmin" + show-snapshot-action="isAdmin" snapshot-action="triggerSnapshot" edit-action="goToEdit" is-admin="isAdmin" diff --git a/app/portainer/views/registries/registries.html b/app/portainer/views/registries/registries.html index c6a13584e..22f89ade9 100644 --- a/app/portainer/views/registries/registries.html +++ b/app/portainer/views/registries/registries.html @@ -7,7 +7,7 @@ Registry management -
+
@@ -79,7 +79,7 @@ dataset="registries" table-key="registries" order-by="Name" - access-management="!applicationState.application.authentication || isAdmin" + access-management="isAdmin" remove-action="removeAction" registry-management="registryManagementAvailable" can-browse="canBrowse" diff --git a/app/portainer/views/registries/registriesController.js b/app/portainer/views/registries/registriesController.js index f4f6b49ea..72e9e51eb 100644 --- a/app/portainer/views/registries/registriesController.js +++ b/app/portainer/views/registries/registriesController.js @@ -81,10 +81,7 @@ angular.module('portainer.app').controller('RegistriesController', [ $scope.registries = data.registries; $scope.dockerhub = data.dockerhub; $scope.registryManagementAvailable = data.registryManagement; - var authenticationEnabled = $scope.applicationState.application.authentication; - if (authenticationEnabled) { - $scope.isAdmin = Authentication.isAdmin(); - } + $scope.isAdmin = Authentication.isAdmin(); }) .catch(function error(err) { $scope.registries = []; diff --git a/app/portainer/views/settings/authentication/settingsAuthentication.html b/app/portainer/views/settings/authentication/settingsAuthentication.html index 5270ca50b..be58b78da 100644 --- a/app/portainer/views/settings/authentication/settingsAuthentication.html +++ b/app/portainer/views/settings/authentication/settingsAuthentication.html @@ -9,6 +9,28 @@
+
+ Configuration +
+
+ +
+ +
+
+
+ + Changing from default is only recommended if you have additional layers of authentication in front of Portainer. + +
Authentication method
diff --git a/app/portainer/views/settings/authentication/settingsAuthenticationController.js b/app/portainer/views/settings/authentication/settingsAuthenticationController.js index 34e6c4124..97eb2a5dc 100644 --- a/app/portainer/views/settings/authentication/settingsAuthenticationController.js +++ b/app/portainer/views/settings/authentication/settingsAuthenticationController.js @@ -14,9 +14,32 @@ angular.module('portainer.app').controller('SettingsAuthenticationController', [ uploadInProgress: false, connectivityCheckInProgress: false, actionInProgress: false, + availableUserSessionTimeoutOptions: [ + { + key: '1 hour', + value: '1h', + }, + { + key: '4 hours', + value: '4h', + }, + { + key: '8 hours', + value: '8h', + }, + { + key: '24 hours', + value: '24h', + }, + { key: '1 week', value: `${24 * 7}h` }, + { key: '1 month', value: `${24 * 30}h` }, + { key: '6 months', value: `${24 * 30 * 6}h` }, + { key: '1 year', value: `${24 * 30 * 12}h` }, + ], }; $scope.formValues = { + UserSessionTimeout: $scope.state.availableUserSessionTimeoutOptions[0], TLSCACert: '', LDAPSettings: { AnonymousMode: true, diff --git a/app/portainer/views/sidebar/sidebar.html b/app/portainer/views/sidebar/sidebar.html index 6e57ac2c5..2ba2696af 100644 --- a/app/portainer/views/sidebar/sidebar.html +++ b/app/portainer/views/sidebar/sidebar.html @@ -19,7 +19,7 @@ endpoint-api-version="applicationState.endpoint.apiVersion" swarm-management="applicationState.endpoint.mode.provider === 'DOCKER_SWARM_MODE' && applicationState.endpoint.mode.role === 'MANAGER'" standalone-management="applicationState.endpoint.mode.provider === 'DOCKER_STANDALONE' || applicationState.endpoint.mode.provider === 'VMWARE_VIC'" - admin-access="!applicationState.application.authentication || isAdmin" + admin-access="isAdmin" offline-mode="endpointState.OfflineMode" >
- - - - - -
- +
@@ -136,7 +136,7 @@
- +