From b4e38b6b38488a0af90be745a037fd01ac8beced Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Sat, 9 May 2020 10:18:47 +1200 Subject: [PATCH] feat(users): lowercase username --- api/bolt/migrator/migrate_dbversion22.go | 24 +++++++++++++++++++- api/http/handler/auth/authenticate.go | 6 +++-- api/http/handler/users/admin_init.go | 3 ++- api/http/handler/users/user_create.go | 7 ++++-- app/portainer/views/users/usersController.js | 21 +++++++++-------- 5 files changed, 46 insertions(+), 15 deletions(-) diff --git a/api/bolt/migrator/migrate_dbversion22.go b/api/bolt/migrator/migrate_dbversion22.go index f2e3c2b6c..e65723b2d 100644 --- a/api/bolt/migrator/migrate_dbversion22.go +++ b/api/bolt/migrator/migrate_dbversion22.go @@ -1,6 +1,10 @@ package migrator -import "github.com/portainer/portainer/api" +import ( + "strings" + + "github.com/portainer/portainer/api" +) func (m *Migrator) updateEndointsAndEndpointsGroupsToDBVersion23() error { tags, err := m.tagService.Tags() @@ -55,3 +59,21 @@ func (m *Migrator) updateEndointsAndEndpointsGroupsToDBVersion23() error { return nil } + +func (m *Migrator) updateUsersToDBVersion23() error { + legacyUsers, err := m.userService.Users() + if err != nil { + return err + } + + for _, user := range legacyUsers { + user.Username = strings.ToLower(user.Username) + + err = m.userService.UpdateUser(user.ID, &user) + if err != nil { + return err + } + } + + return nil +} diff --git a/api/http/handler/auth/authenticate.go b/api/http/handler/auth/authenticate.go index 8e51f65db..9717ae818 100644 --- a/api/http/handler/auth/authenticate.go +++ b/api/http/handler/auth/authenticate.go @@ -47,7 +47,9 @@ func (handler *Handler) authenticate(w http.ResponseWriter, r *http.Request) *ht return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve settings from the database", err} } - u, err := handler.UserService.UserByUsername(payload.Username) + userName := strings.ToLower(payload.Username) + + u, err := handler.UserService.UserByUsername(userName) if err != nil && err != portainer.ErrObjectNotFound { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve a user with the specified username from the database", err} } @@ -58,7 +60,7 @@ func (handler *Handler) authenticate(w http.ResponseWriter, r *http.Request) *ht if settings.AuthenticationMethod == portainer.AuthenticationLDAP { if u == nil && settings.LDAPSettings.AutoCreateUsers { - return handler.authenticateLDAPAndCreateUser(w, payload.Username, payload.Password, &settings.LDAPSettings) + return handler.authenticateLDAPAndCreateUser(w, userName, payload.Password, &settings.LDAPSettings) } else if u == nil && !settings.LDAPSettings.AutoCreateUsers { return &httperror.HandlerError{http.StatusUnprocessableEntity, "Invalid credentials", portainer.ErrUnauthorized} } diff --git a/api/http/handler/users/admin_init.go b/api/http/handler/users/admin_init.go index a57e95f62..5bba26afe 100644 --- a/api/http/handler/users/admin_init.go +++ b/api/http/handler/users/admin_init.go @@ -2,6 +2,7 @@ package users import ( "net/http" + "strings" "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" @@ -43,7 +44,7 @@ func (handler *Handler) adminInit(w http.ResponseWriter, r *http.Request) *httpe } user := &portainer.User{ - Username: payload.Username, + Username: strings.ToLower(payload.Username), Role: portainer.AdministratorRole, PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(), } diff --git a/api/http/handler/users/user_create.go b/api/http/handler/users/user_create.go index 582ca084d..1539f0a3c 100644 --- a/api/http/handler/users/user_create.go +++ b/api/http/handler/users/user_create.go @@ -2,6 +2,7 @@ package users import ( "net/http" + "strings" "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" @@ -49,7 +50,9 @@ func (handler *Handler) userCreate(w http.ResponseWriter, r *http.Request) *http return &httperror.HandlerError{http.StatusForbidden, "Permission denied to create administrator user", portainer.ErrResourceAccessDenied} } - user, err := handler.UserService.UserByUsername(payload.Username) + userName := strings.ToLower(payload.Username) + + user, err := handler.UserService.UserByUsername(userName) if err != nil && err != portainer.ErrObjectNotFound { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve users from the database", err} } @@ -58,7 +61,7 @@ func (handler *Handler) userCreate(w http.ResponseWriter, r *http.Request) *http } user = &portainer.User{ - Username: payload.Username, + Username: strings.ToLower(userName), Role: portainer.UserRole(payload.Role), PortainerAuthorizations: portainer.DefaultPortainerAuthorizations(), } diff --git a/app/portainer/views/users/usersController.js b/app/portainer/views/users/usersController.js index acbb9b237..f6f985413 100644 --- a/app/portainer/views/users/usersController.js +++ b/app/portainer/views/users/usersController.js @@ -27,21 +27,24 @@ angular.module('portainer.app').controller('UsersController', [ }; $scope.checkUsernameValidity = function () { - var valid = true; - for (var i = 0; i < $scope.users.length; i++) { - if ($scope.formValues.Username === $scope.users[i].Username) { - valid = false; - break; + const currentUsername = _.toLower($scope.formValues.Username); + let validUsername = true; + + _.forEach($scope.users, (user) => { + if (user.Username === currentUsername) { + validUsername = false; + return; } - } - $scope.state.validUsername = valid; - $scope.state.userCreationError = valid ? '' : 'Username already taken'; + }); + + $scope.state.validUsername = validUsername; + $scope.state.userCreationError = validUsername ? '' : 'Username already taken'; }; $scope.addUser = function () { $scope.state.actionInProgress = true; $scope.state.userCreationError = ''; - var username = $scope.formValues.Username; + var username = _.toLower($scope.formValues.Username); var password = $scope.formValues.Password; var role = $scope.formValues.Administrator ? 1 : 2; var teamIds = [];