diff --git a/api/bolt/migrator/migrate_dbversion12.go b/api/bolt/migrator/migrate_dbversion12.go index 465c10682..0d2bf0554 100644 --- a/api/bolt/migrator/migrate_dbversion12.go +++ b/api/bolt/migrator/migrate_dbversion12.go @@ -8,6 +8,7 @@ func (m *Migrator) updateSettingsToVersion13() error { return err } + legacySettings.LDAPSettings.AutoCreateUsers = false legacySettings.LDAPSettings.GroupSearchSettings = []portainer.LDAPGroupSearchSettings{ portainer.LDAPGroupSearchSettings{}, } diff --git a/api/bolt/migrator/migrator.go b/api/bolt/migrator/migrator.go index efae952d8..5b03aa806 100644 --- a/api/bolt/migrator/migrator.go +++ b/api/bolt/migrator/migrator.go @@ -170,6 +170,7 @@ func (m *Migrator) Migrate() error { } } + // Portainer 1.18.2-dev if m.currentDBVersion < 13 { err := m.updateSettingsToVersion13() if err != nil { diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 01a73d41f..567ff4c9e 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -164,7 +164,8 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL LogoURL: *flags.Logo, AuthenticationMethod: portainer.AuthenticationInternal, LDAPSettings: portainer.LDAPSettings{ - TLSConfig: portainer.TLSConfiguration{}, + AutoCreateUsers: true, + TLSConfig: portainer.TLSConfiguration{}, SearchSettings: []portainer.LDAPSearchSettings{ portainer.LDAPSearchSettings{}, }, diff --git a/api/http/handler/auth/authenticate.go b/api/http/handler/auth/authenticate.go index e473e60fc..cf928357b 100644 --- a/api/http/handler/auth/authenticate.go +++ b/api/http/handler/auth/authenticate.go @@ -3,6 +3,7 @@ package auth import ( "log" "net/http" + "strings" "github.com/asaskevich/govalidator" "github.com/portainer/portainer" @@ -56,8 +57,10 @@ func (handler *Handler) authenticate(w http.ResponseWriter, r *http.Request) *ht } if settings.AuthenticationMethod == portainer.AuthenticationLDAP { - if u == nil { + if u == nil && settings.LDAPSettings.AutoCreateUsers { return handler.authenticateLDAPAndCreateUser(w, payload.Username, payload.Password, &settings.LDAPSettings) + } else if u == nil && !settings.LDAPSettings.AutoCreateUsers { + return &httperror.HandlerError{http.StatusUnprocessableEntity, "Invalid credentials", portainer.ErrUnauthorized} } return handler.authenticateLDAP(w, u, payload.Password, &settings.LDAPSettings) } @@ -167,7 +170,7 @@ func (handler *Handler) addUserIntoTeams(user *portainer.User, settings *portain func teamExists(teamName string, ldapGroups []string) bool { for _, group := range ldapGroups { - if group == teamName { + if strings.ToLower(group) == strings.ToLower(teamName) { return true } } diff --git a/api/http/handler/settings/settings_public.go b/api/http/handler/settings/settings_public.go index 690688079..c2ee2a616 100644 --- a/api/http/handler/settings/settings_public.go +++ b/api/http/handler/settings/settings_public.go @@ -13,7 +13,6 @@ type publicSettingsResponse struct { AuthenticationMethod portainer.AuthenticationMethod `json:"AuthenticationMethod"` AllowBindMountsForRegularUsers bool `json:"AllowBindMountsForRegularUsers"` AllowPrivilegedModeForRegularUsers bool `json:"AllowPrivilegedModeForRegularUsers"` - SnapshotInterval string `json:"SnapshotInterval"` } // GET request on /api/settings/public @@ -28,7 +27,6 @@ func (handler *Handler) settingsPublic(w http.ResponseWriter, r *http.Request) * AuthenticationMethod: settings.AuthenticationMethod, AllowBindMountsForRegularUsers: settings.AllowBindMountsForRegularUsers, AllowPrivilegedModeForRegularUsers: settings.AllowPrivilegedModeForRegularUsers, - SnapshotInterval: settings.SnapshotInterval, } return response.JSON(w, publicSettings) diff --git a/api/portainer.go b/api/portainer.go index 610e0bdac..d2a75e345 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -53,6 +53,7 @@ type ( StartTLS bool `json:"StartTLS"` SearchSettings []LDAPSearchSettings `json:"SearchSettings"` GroupSearchSettings []LDAPGroupSearchSettings `json:"GroupSearchSettings"` + AutoCreateUsers bool `json:"AutoCreateUsers"` } // TLSConfiguration represents a TLS configuration. diff --git a/api/swagger.yaml b/api/swagger.yaml index fefd61d33..7b556b0eb 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -2942,6 +2942,10 @@ definitions: type: "array" items: $ref: "#/definitions/LDAPGroupSearchSettings" + AutoCreateUsers: + type: "boolean" + example: "true" + description: "Automatically provision users and assign them to matching LDAP group names" Settings: type: "object" diff --git a/app/portainer/models/settings/ldapSettings.js b/app/portainer/models/settings.js similarity index 54% rename from app/portainer/models/settings/ldapSettings.js rename to app/portainer/models/settings.js index 3bd02225c..16ec568c2 100644 --- a/app/portainer/models/settings/ldapSettings.js +++ b/app/portainer/models/settings.js @@ -1,9 +1,20 @@ +function SettingsViewModel(data) { + this.LogoURL = data.LogoURL; + this.BlackListedLabels = data.BlackListedLabels; + this.AuthenticationMethod = data.AuthenticationMethod; + this.LDAPSettings = data.LDAPSettings; + this.AllowBindMountsForRegularUsers = data.AllowBindMountsForRegularUsers; + this.AllowPrivilegedModeForRegularUsers = data.AllowPrivilegedModeForRegularUsers; + this.SnapshotInterval = data.SnapshotInterval; +} + function LDAPSettingsViewModel(data) { this.ReaderDN = data.ReaderDN; this.Password = data.Password; this.URL = data.URL; this.SearchSettings = data.SearchSettings; this.GroupSearchSettings = data.GroupSearchSettings; + this.AutoCreateUsers = data.AutoCreateUsers; } function LDAPSearchSettings(BaseDN, UsernameAttribute, Filter) { diff --git a/app/portainer/models/settings/settings.js b/app/portainer/models/settings/settings.js deleted file mode 100644 index a791a4ca2..000000000 --- a/app/portainer/models/settings/settings.js +++ /dev/null @@ -1,9 +0,0 @@ -function SettingsViewModel(data) { - this.LogoURL = data.LogoURL; - this.BlackListedLabels = data.BlackListedLabels; - this.AuthenticationMethod = data.AuthenticationMethod; - this.LDAPSettings = data.LDAPSettings; - this.AllowBindMountsForRegularUsers = data.AllowBindMountsForRegularUsers; - this.AllowPrivilegedModeForRegularUsers = data.AllowPrivilegedModeForRegularUsers; - this.SnapshotInterval = data.SnapshotInterval; -} diff --git a/app/portainer/views/settings/authentication/settingsAuthentication.html b/app/portainer/views/settings/authentication/settingsAuthentication.html index fad5137d3..72db0edef 100644 --- a/app/portainer/views/settings/authentication/settingsAuthentication.html +++ b/app/portainer/views/settings/authentication/settingsAuthentication.html @@ -50,10 +50,6 @@
When using LDAP authentication, Portainer will delegate user authentication to a LDAP server and fallback to internal authentication if LDAP authentication fails. -

- - Portainer will create user(s) automatically with standard user role and assign them to team(s) which matches to LDAP group name(s). -

@@ -182,6 +178,25 @@ +
+ Automatic user provisioning +
+
+ + With automatic user provisioning enabled, Portainer will create user(s) automatically with standard user role and assign them to team(s) which matches to LDAP group name(s). If disabled, users must be created in Portainer beforehand. + +
+
+
+ + +
+
+
User search configurations