mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-25 01:10:37 +00:00
Add restricted user filter to LDAP authentication (#10600)
* Add restricted user filter to LDAP authentification * Fix unit test cases
This commit is contained in:
parent
be544e8e6a
commit
37c3db7be6
12 changed files with 146 additions and 52 deletions
|
@ -61,6 +61,10 @@ var (
|
||||||
Name: "admin-filter",
|
Name: "admin-filter",
|
||||||
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
|
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "restricted-filter",
|
||||||
|
Usage: "An LDAP filter specifying if a user should be given restricted status.",
|
||||||
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "allow-deactivate-all",
|
Name: "allow-deactivate-all",
|
||||||
Usage: "Allow empty search results to deactivate all users.",
|
Usage: "Allow empty search results to deactivate all users.",
|
||||||
|
@ -235,6 +239,9 @@ func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error {
|
||||||
if c.IsSet("admin-filter") {
|
if c.IsSet("admin-filter") {
|
||||||
config.Source.AdminFilter = c.String("admin-filter")
|
config.Source.AdminFilter = c.String("admin-filter")
|
||||||
}
|
}
|
||||||
|
if c.IsSet("restricted-filter") {
|
||||||
|
config.Source.RestrictedFilter = c.String("restricted-filter")
|
||||||
|
}
|
||||||
if c.IsSet("allow-deactivate-all") {
|
if c.IsSet("allow-deactivate-all") {
|
||||||
config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all")
|
config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all")
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||||
"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
|
"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
|
||||||
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
|
"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
"--username-attribute", "uid-bind full",
|
"--username-attribute", "uid-bind full",
|
||||||
"--firstname-attribute", "givenName-bind full",
|
"--firstname-attribute", "givenName-bind full",
|
||||||
"--surname-attribute", "sn-bind full",
|
"--surname-attribute", "sn-bind full",
|
||||||
|
@ -74,6 +75,7 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||||
SearchPageSize: 99,
|
SearchPageSize: 99,
|
||||||
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
|
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -265,6 +267,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
|
"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
|
||||||
"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
||||||
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
|
"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
"--username-attribute", "uid-simple full",
|
"--username-attribute", "uid-simple full",
|
||||||
"--firstname-attribute", "givenName-simple full",
|
"--firstname-attribute", "givenName-simple full",
|
||||||
"--surname-attribute", "sn-simple full",
|
"--surname-attribute", "sn-simple full",
|
||||||
|
@ -292,6 +295,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
AttributeSSHPublicKey: "publickey-simple full",
|
AttributeSSHPublicKey: "publickey-simple full",
|
||||||
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
||||||
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
|
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -499,6 +503,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
|
"--user-search-base", "ou=Users,dc=full-domain-bind,dc=org",
|
||||||
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
|
"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
"--username-attribute", "uid-bind full",
|
"--username-attribute", "uid-bind full",
|
||||||
"--firstname-attribute", "givenName-bind full",
|
"--firstname-attribute", "givenName-bind full",
|
||||||
"--surname-attribute", "sn-bind full",
|
"--surname-attribute", "sn-bind full",
|
||||||
|
@ -543,6 +548,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
SearchPageSize: 99,
|
SearchPageSize: 99,
|
||||||
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
Filter: "(memberOf=cn=user-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
|
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -978,6 +984,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
|
"--user-search-base", "ou=Users,dc=full-domain-simple,dc=org",
|
||||||
"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
"--user-filter", "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
||||||
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
"--admin-filter", "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
|
"--restricted-filter", "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
"--username-attribute", "uid-simple full",
|
"--username-attribute", "uid-simple full",
|
||||||
"--firstname-attribute", "givenName-simple full",
|
"--firstname-attribute", "givenName-simple full",
|
||||||
"--surname-attribute", "sn-simple full",
|
"--surname-attribute", "sn-simple full",
|
||||||
|
@ -1006,6 +1013,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
AttributeSSHPublicKey: "publickey-simple full",
|
AttributeSSHPublicKey: "publickey-simple full",
|
||||||
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
Filter: "(&(objectClass=posixAccount)(full-simple-cn=%s))",
|
||||||
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
|
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-simple,dc=org)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -134,6 +134,7 @@ Admin operations:
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for. Required.
|
- `--user-search-base value`: The LDAP base at which user accounts will be searched for. Required.
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
||||||
|
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
||||||
|
@ -158,6 +159,7 @@ Admin operations:
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
||||||
|
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
||||||
|
@ -182,6 +184,7 @@ Admin operations:
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate. Required.
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
||||||
|
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
||||||
|
@ -202,6 +205,7 @@ Admin operations:
|
||||||
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
- `--user-search-base value`: The LDAP base at which user accounts will be searched for.
|
||||||
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
- `--user-filter value`: An LDAP filter declaring how to find the user record that is attempting to authenticate.
|
||||||
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
- `--admin-filter value`: An LDAP filter specifying if a user should be given administrator privileges.
|
||||||
|
- `--restricted-filter value`: An LDAP filter specifying if a user should be given restricted status.
|
||||||
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
- `--username-attribute value`: The attribute of the user’s LDAP record containing the user name.
|
||||||
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
- `--firstname-attribute value`: The attribute of the user’s LDAP record containing the user’s first name.
|
||||||
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
- `--surname-attribute value`: The attribute of the user’s LDAP record containing the user’s surname.
|
||||||
|
|
|
@ -18,13 +18,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ldapUser struct {
|
type ldapUser struct {
|
||||||
UserName string
|
UserName string
|
||||||
Password string
|
Password string
|
||||||
FullName string
|
FullName string
|
||||||
Email string
|
Email string
|
||||||
OtherEmails []string
|
OtherEmails []string
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
SSHKeys []string
|
IsRestricted bool
|
||||||
|
SSHKeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitLDAPUsers = []ldapUser{
|
var gitLDAPUsers = []ldapUser{
|
||||||
|
@ -55,10 +56,11 @@ var gitLDAPUsers = []ldapUser{
|
||||||
Email: "fry@planetexpress.com",
|
Email: "fry@planetexpress.com",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserName: "leela",
|
UserName: "leela",
|
||||||
Password: "leela",
|
Password: "leela",
|
||||||
FullName: "Leela Turanga",
|
FullName: "Leela Turanga",
|
||||||
Email: "leela@planetexpress.com",
|
Email: "leela@planetexpress.com",
|
||||||
|
IsRestricted: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UserName: "bender",
|
UserName: "bender",
|
||||||
|
@ -109,6 +111,7 @@ func addAuthSourceLDAP(t *testing.T, sshKeyAttribute string) {
|
||||||
"user_base": "ou=people,dc=planetexpress,dc=com",
|
"user_base": "ou=people,dc=planetexpress,dc=com",
|
||||||
"filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
|
"filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))",
|
||||||
"admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
|
"admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)",
|
||||||
|
"restricted_filter": "(uid=leela)",
|
||||||
"attribute_username": "uid",
|
"attribute_username": "uid",
|
||||||
"attribute_name": "givenName",
|
"attribute_name": "givenName",
|
||||||
"attribute_surname": "sn",
|
"attribute_surname": "sn",
|
||||||
|
@ -173,6 +176,11 @@ func TestLDAPUserSync(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-square-o"))
|
assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-square-o"))
|
||||||
}
|
}
|
||||||
|
if u.IsRestricted {
|
||||||
|
assert.True(t, tds.Find("td:nth-child(6) i").HasClass("fa-check-square-o"))
|
||||||
|
} else {
|
||||||
|
assert.True(t, tds.Find("td:nth-child(6) i").HasClass("fa-square-o"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if no users exist
|
// Check if no users exist
|
||||||
|
|
|
@ -475,13 +475,23 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*Use
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if user != nil &&
|
if user != nil && !user.ProhibitLogin {
|
||||||
!user.ProhibitLogin && len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
|
cols := make([]string, 0)
|
||||||
// Change existing admin flag only if AdminFilter option is set
|
if len(source.LDAP().AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
|
||||||
user.IsAdmin = sr.IsAdmin
|
// Change existing admin flag only if AdminFilter option is set
|
||||||
err = UpdateUserCols(user, "is_admin")
|
user.IsAdmin = sr.IsAdmin
|
||||||
if err != nil {
|
cols = append(cols, "is_admin")
|
||||||
return nil, err
|
}
|
||||||
|
if !user.IsAdmin && len(source.LDAP().RestrictedFilter) > 0 && user.IsRestricted != sr.IsRestricted {
|
||||||
|
// Change existing restricted flag only if RestrictedFilter option is set
|
||||||
|
user.IsRestricted = sr.IsRestricted
|
||||||
|
cols = append(cols, "is_restricted")
|
||||||
|
}
|
||||||
|
if len(cols) > 0 {
|
||||||
|
err = UpdateUserCols(user, cols...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,15 +514,16 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*Use
|
||||||
}
|
}
|
||||||
|
|
||||||
user = &User{
|
user = &User{
|
||||||
LowerName: strings.ToLower(sr.Username),
|
LowerName: strings.ToLower(sr.Username),
|
||||||
Name: sr.Username,
|
Name: sr.Username,
|
||||||
FullName: composeFullName(sr.Name, sr.Surname, sr.Username),
|
FullName: composeFullName(sr.Name, sr.Surname, sr.Username),
|
||||||
Email: sr.Mail,
|
Email: sr.Mail,
|
||||||
LoginType: source.Type,
|
LoginType: source.Type,
|
||||||
LoginSource: source.ID,
|
LoginSource: source.ID,
|
||||||
LoginName: login,
|
LoginName: login,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
IsAdmin: sr.IsAdmin,
|
IsAdmin: sr.IsAdmin,
|
||||||
|
IsRestricted: sr.IsRestricted,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := CreateUser(user)
|
err := CreateUser(user)
|
||||||
|
|
|
@ -1875,15 +1875,16 @@ func SyncExternalUsers(ctx context.Context) {
|
||||||
log.Trace("SyncExternalUsers[%s]: Creating user %s", s.Name, su.Username)
|
log.Trace("SyncExternalUsers[%s]: Creating user %s", s.Name, su.Username)
|
||||||
|
|
||||||
usr = &User{
|
usr = &User{
|
||||||
LowerName: strings.ToLower(su.Username),
|
LowerName: strings.ToLower(su.Username),
|
||||||
Name: su.Username,
|
Name: su.Username,
|
||||||
FullName: fullName,
|
FullName: fullName,
|
||||||
LoginType: s.Type,
|
LoginType: s.Type,
|
||||||
LoginSource: s.ID,
|
LoginSource: s.ID,
|
||||||
LoginName: su.Username,
|
LoginName: su.Username,
|
||||||
Email: su.Mail,
|
Email: su.Mail,
|
||||||
IsAdmin: su.IsAdmin,
|
IsAdmin: su.IsAdmin,
|
||||||
IsActive: true,
|
IsRestricted: su.IsRestricted,
|
||||||
|
IsActive: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = CreateUser(usr)
|
err = CreateUser(usr)
|
||||||
|
@ -1906,6 +1907,7 @@ func SyncExternalUsers(ctx context.Context) {
|
||||||
|
|
||||||
// Check if user data has changed
|
// Check if user data has changed
|
||||||
if (len(s.LDAP().AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) ||
|
if (len(s.LDAP().AdminFilter) > 0 && usr.IsAdmin != su.IsAdmin) ||
|
||||||
|
(len(s.LDAP().RestrictedFilter) > 0 && usr.IsRestricted != su.IsRestricted) ||
|
||||||
!strings.EqualFold(usr.Email, su.Mail) ||
|
!strings.EqualFold(usr.Email, su.Mail) ||
|
||||||
usr.FullName != fullName ||
|
usr.FullName != fullName ||
|
||||||
!usr.IsActive {
|
!usr.IsActive {
|
||||||
|
@ -1918,9 +1920,13 @@ func SyncExternalUsers(ctx context.Context) {
|
||||||
if len(s.LDAP().AdminFilter) > 0 {
|
if len(s.LDAP().AdminFilter) > 0 {
|
||||||
usr.IsAdmin = su.IsAdmin
|
usr.IsAdmin = su.IsAdmin
|
||||||
}
|
}
|
||||||
|
// Change existing restricted flag only if RestrictedFilter option is set
|
||||||
|
if !usr.IsAdmin && len(s.LDAP().RestrictedFilter) > 0 {
|
||||||
|
usr.IsRestricted = su.IsRestricted
|
||||||
|
}
|
||||||
usr.IsActive = true
|
usr.IsActive = true
|
||||||
|
|
||||||
err = UpdateUserCols(usr, "full_name", "email", "is_admin", "is_active")
|
err = UpdateUserCols(usr, "full_name", "email", "is_admin", "is_restricted", "is_active")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", s.Name, usr.Name, err)
|
log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", s.Name, usr.Name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type AuthenticationForm struct {
|
||||||
SearchPageSize int
|
SearchPageSize int
|
||||||
Filter string
|
Filter string
|
||||||
AdminFilter string
|
AdminFilter string
|
||||||
|
RestrictedFilter string
|
||||||
AllowDeactivateAll bool
|
AllowDeactivateAll bool
|
||||||
IsActive bool
|
IsActive bool
|
||||||
IsSyncEnabled bool
|
IsSyncEnabled bool
|
||||||
|
|
|
@ -46,6 +46,7 @@ type Source struct {
|
||||||
SearchPageSize uint32 // Search with paging page size
|
SearchPageSize uint32 // Search with paging page size
|
||||||
Filter string // Query filter to validate entry
|
Filter string // Query filter to validate entry
|
||||||
AdminFilter string // Query filter to check if user is admin
|
AdminFilter string // Query filter to check if user is admin
|
||||||
|
RestrictedFilter string // Query filter to check if user is restricted
|
||||||
Enabled bool // if this source is disabled
|
Enabled bool // if this source is disabled
|
||||||
AllowDeactivateAll bool // Allow an empty search response to deactivate all users from this source
|
AllowDeactivateAll bool // Allow an empty search response to deactivate all users from this source
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,7 @@ type SearchResult struct {
|
||||||
Mail string // E-mail address
|
Mail string // E-mail address
|
||||||
SSHPublicKey []string // SSH Public Key
|
SSHPublicKey []string // SSH Public Key
|
||||||
IsAdmin bool // if user is administrator
|
IsAdmin bool // if user is administrator
|
||||||
|
IsRestricted bool // if user is restricted
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
|
func (ls *Source) sanitizedUserQuery(username string) (string, bool) {
|
||||||
|
@ -153,22 +155,48 @@ func bindUser(l *ldap.Conn, userDN, passwd string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAdmin(l *ldap.Conn, ls *Source, userDN string) bool {
|
func checkAdmin(l *ldap.Conn, ls *Source, userDN string) bool {
|
||||||
if len(ls.AdminFilter) > 0 {
|
if len(ls.AdminFilter) == 0 {
|
||||||
log.Trace("Checking admin with filter %s and base %s", ls.AdminFilter, userDN)
|
return false
|
||||||
search := ldap.NewSearchRequest(
|
}
|
||||||
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
|
log.Trace("Checking admin with filter %s and base %s", ls.AdminFilter, userDN)
|
||||||
[]string{ls.AttributeName},
|
search := ldap.NewSearchRequest(
|
||||||
nil)
|
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
|
||||||
|
[]string{ls.AttributeName},
|
||||||
|
nil)
|
||||||
|
|
||||||
sr, err := l.Search(search)
|
sr, err := l.Search(search)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LDAP Admin Search failed unexpectedly! (%v)", err)
|
log.Error("LDAP Admin Search failed unexpectedly! (%v)", err)
|
||||||
} else if len(sr.Entries) < 1 {
|
} else if len(sr.Entries) < 1 {
|
||||||
log.Trace("LDAP Admin Search found no matching entries.")
|
log.Trace("LDAP Admin Search found no matching entries.")
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRestricted(l *ldap.Conn, ls *Source, userDN string) bool {
|
||||||
|
if len(ls.RestrictedFilter) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ls.RestrictedFilter == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
log.Trace("Checking restricted with filter %s and base %s", ls.RestrictedFilter, userDN)
|
||||||
|
search := ldap.NewSearchRequest(
|
||||||
|
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.RestrictedFilter,
|
||||||
|
[]string{ls.AttributeName},
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := l.Search(search)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("LDAP Restrictred Search failed unexpectedly! (%v)", err)
|
||||||
|
} else if len(sr.Entries) < 1 {
|
||||||
|
log.Trace("LDAP Restricted Search found no matching entries.")
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -284,6 +312,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
||||||
sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
sshPublicKey = sr.Entries[0].GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||||
}
|
}
|
||||||
isAdmin := checkAdmin(l, ls, userDN)
|
isAdmin := checkAdmin(l, ls, userDN)
|
||||||
|
var isRestricted bool
|
||||||
|
if !isAdmin {
|
||||||
|
isRestricted = checkRestricted(l, ls, userDN)
|
||||||
|
}
|
||||||
|
|
||||||
if !directBind && ls.AttributesInBind {
|
if !directBind && ls.AttributesInBind {
|
||||||
// binds user (checking password) after looking-up attributes in BindDN context
|
// binds user (checking password) after looking-up attributes in BindDN context
|
||||||
|
@ -300,6 +332,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) *SearchResul
|
||||||
Mail: mail,
|
Mail: mail,
|
||||||
SSHPublicKey: sshPublicKey,
|
SSHPublicKey: sshPublicKey,
|
||||||
IsAdmin: isAdmin,
|
IsAdmin: isAdmin,
|
||||||
|
IsRestricted: isRestricted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,6 +397,9 @@ func (ls *Source) SearchEntries() ([]*SearchResult, error) {
|
||||||
Mail: v.GetAttributeValue(ls.AttributeMail),
|
Mail: v.GetAttributeValue(ls.AttributeMail),
|
||||||
IsAdmin: checkAdmin(l, ls, v.DN),
|
IsAdmin: checkAdmin(l, ls, v.DN),
|
||||||
}
|
}
|
||||||
|
if !result[i].IsAdmin {
|
||||||
|
result[i].IsRestricted = checkRestricted(l, ls, v.DN)
|
||||||
|
}
|
||||||
if isAttributeSSHPublicKeySet {
|
if isAttributeSSHPublicKeySet {
|
||||||
result[i].SSHPublicKey = v.GetAttributeValues(ls.AttributeSSHPublicKey)
|
result[i].SSHPublicKey = v.GetAttributeValues(ls.AttributeSSHPublicKey)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1893,6 +1893,8 @@ auths.use_paged_search = Use Paged Search
|
||||||
auths.search_page_size = Page Size
|
auths.search_page_size = Page Size
|
||||||
auths.filter = User Filter
|
auths.filter = User Filter
|
||||||
auths.admin_filter = Admin Filter
|
auths.admin_filter = Admin Filter
|
||||||
|
auths.restricted_filter = Restricted Filter
|
||||||
|
auths.restricted_filter_helper = Leave empty to not set any users as restricted. Use an asterisk ('*') to set all users that do not match Admin Filter as restricted.
|
||||||
auths.ms_ad_sa = MS AD Search Attributes
|
auths.ms_ad_sa = MS AD Search Attributes
|
||||||
auths.smtp_auth = SMTP Authentication Type
|
auths.smtp_auth = SMTP Authentication Type
|
||||||
auths.smtphost = SMTP Host
|
auths.smtphost = SMTP Host
|
||||||
|
|
|
@ -130,6 +130,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
|
||||||
SearchPageSize: pageSize,
|
SearchPageSize: pageSize,
|
||||||
Filter: form.Filter,
|
Filter: form.Filter,
|
||||||
AdminFilter: form.AdminFilter,
|
AdminFilter: form.AdminFilter,
|
||||||
|
RestrictedFilter: form.RestrictedFilter,
|
||||||
AllowDeactivateAll: form.AllowDeactivateAll,
|
AllowDeactivateAll: form.AllowDeactivateAll,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,6 +74,11 @@
|
||||||
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
||||||
<input id="admin_filter" name="admin_filter" value="{{$cfg.AdminFilter}}">
|
<input id="admin_filter" name="admin_filter" value="{{$cfg.AdminFilter}}">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="restricted_filter">{{.i18n.Tr "admin.auths.restricted_filter"}}</label>
|
||||||
|
<input id="restricted_filter" name="restricted_filter" value="{{$cfg.RestrictedFilter}}">
|
||||||
|
<p class="help">{{.i18n.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
||||||
<input id="attribute_username" name="attribute_username" value="{{$cfg.AttributeUsername}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
<input id="attribute_username" name="attribute_username" value="{{$cfg.AttributeUsername}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||||
|
|
|
@ -46,6 +46,11 @@
|
||||||
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
||||||
<input id="admin_filter" name="admin_filter" value="{{.admin_filter}}">
|
<input id="admin_filter" name="admin_filter" value="{{.admin_filter}}">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="restricted_filter">{{.i18n.Tr "admin.auths.restricted_filter"}}</label>
|
||||||
|
<input id="restricted_filter" name="admin_filter" value="{{.restricted_filter}}">
|
||||||
|
<p class="help">{{.i18n.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
||||||
<input id="attribute_username" name="attribute_username" value="{{.attribute_username}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
<input id="attribute_username" name="attribute_username" value="{{.attribute_username}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||||
|
|
Loading…
Reference in a new issue