Set IsAdmin using LDAP

The IsAdmin flag is set based on whether the admin filter
returned any result. The admin filter is applied with the user dn
as the search root.

In the future, we should update IsAdmin as well on each login.
Alternately, we can have a periodic sync operation.
This commit is contained in:
Girish Ramakrishnan 2015-08-18 21:34:03 -07:00
parent 03b85b73af
commit 24d7a86a8d
7 changed files with 38 additions and 8 deletions

View file

@ -761,6 +761,7 @@ auths.attribute_name = First name attribute
auths.attribute_surname = Surname attribute auths.attribute_surname = Surname attribute
auths.attribute_mail = E-mail attribute auths.attribute_mail = E-mail attribute
auths.filter = User Filter auths.filter = User Filter
auths.admin_filter = Admin Filter
auths.ms_ad_sa = Ms Ad SA auths.ms_ad_sa = Ms Ad SA
auths.smtp_auth = SMTP Authorization Type auths.smtp_auth = SMTP Authorization Type
auths.smtphost = SMTP Host auths.smtphost = SMTP Host

View file

@ -257,7 +257,7 @@ func UserSignIn(uname, passwd string) (*User, error) {
// Return the same LoginUserPlain semantic // Return the same LoginUserPlain semantic
// FIXME: https://github.com/gogits/gogs/issues/672 // FIXME: https://github.com/gogits/gogs/issues/672
func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) { func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) {
fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd) fn, sn, mail, admin, logged := cfg.Ldapsource.SearchEntry(name, passwd)
if !logged { if !logged {
// User not in LDAP, do nothing // User not in LDAP, do nothing
return nil, ErrUserNotExist{0, name} return nil, ErrUserNotExist{0, name}
@ -281,6 +281,7 @@ func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAP
LoginName: name, LoginName: name,
Passwd: passwd, Passwd: passwd,
Email: mail, Email: mail,
IsAdmin: admin,
IsActive: true, IsActive: true,
} }
return u, CreateUser(u) return u, CreateUser(u)

View file

@ -23,6 +23,7 @@ type AuthenticationForm struct {
AttributeSurname string AttributeSurname string
AttributeMail string AttributeMail string
Filter string Filter string
AdminFilter string
IsActived bool IsActived bool
SMTPAuth string `form:"smtp_auth"` SMTPAuth string `form:"smtp_auth"`
SMTPHost string `form:"smtp_host"` SMTPHost string `form:"smtp_host"`

View file

@ -26,6 +26,7 @@ type Ldapsource struct {
AttributeSurname string // Surname attribute AttributeSurname string // Surname attribute
AttributeMail string // E-mail attribute AttributeMail string // E-mail attribute
Filter string // Query filter to validate entry Filter string // Query filter to validate entry
AdminFilter string // Query filter to check if user is admin
Enabled bool // if this source is disabled Enabled bool // if this source is disabled
} }
@ -77,17 +78,17 @@ func (ls Ldapsource) FindUserDN(name string) (string, bool) {
} }
// searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter // searchEntry : search an LDAP source if an entry (name, passwd) is valid and in the specific filter
func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, bool) { func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, bool, bool) {
userDN, found := ls.FindUserDN(name) userDN, found := ls.FindUserDN(name)
if !found { if !found {
return "", "", "", false return "", "", "", false, false
} }
l, err := ldapDial(ls) l, err := ldapDial(ls)
if err != nil { if err != nil {
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err) log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
ls.Enabled = false ls.Enabled = false
return "", "", "", false return "", "", "", false, false
} }
defer l.Close() defer l.Close()
@ -96,7 +97,7 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, b
err = l.Bind(userDN, passwd) err = l.Bind(userDN, passwd)
if err != nil { if err != nil {
log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err) log.Debug("LDAP auth. failed for %s, reason: %v", userDN, err)
return "", "", "", false return "", "", "", false, false
} }
log.Trace("Bound successfully with userDN: %s", userDN) log.Trace("Bound successfully with userDN: %s", userDN)
@ -109,16 +110,32 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, b
sr, err := l.Search(search) sr, err := l.Search(search)
if err != nil { if err != nil {
log.Error(4, "LDAP Search failed unexpectedly! (%v)", err) log.Error(4, "LDAP Search failed unexpectedly! (%v)", err)
return "", "", "", false return "", "", "", false, false
} else if len(sr.Entries) < 1 { } else if len(sr.Entries) < 1 {
log.Error(4, "LDAP Search failed unexpectedly! (0 entries)") log.Error(4, "LDAP Search failed unexpectedly! (0 entries)")
return "", "", "", false return "", "", "", false, false
} }
name_attr := sr.Entries[0].GetAttributeValue(ls.AttributeName) name_attr := sr.Entries[0].GetAttributeValue(ls.AttributeName)
sn_attr := sr.Entries[0].GetAttributeValue(ls.AttributeSurname) sn_attr := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
mail_attr := sr.Entries[0].GetAttributeValue(ls.AttributeMail) mail_attr := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
return name_attr, sn_attr, mail_attr, true
search = ldap.NewSearchRequest(
userDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ls.AdminFilter,
[]string{ls.AttributeName},
nil)
sr, err = l.Search(search)
admin_attr := false
if err != nil {
log.Error(4, "LDAP Admin Search failed unexpectedly! (%v)", err)
} else if len(sr.Entries) < 1 {
log.Error(4, "LDAP Admin Search failed")
} else {
admin_attr = true
}
return name_attr, sn_attr, mail_attr, admin_attr, true
} }
func ldapDial(ls Ldapsource) (*ldap.Conn, error) { func ldapDial(ls Ldapsource) (*ldap.Conn, error) {

View file

@ -71,6 +71,7 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
BindPassword: form.BindPassword, BindPassword: form.BindPassword,
UserBase: form.UserBase, UserBase: form.UserBase,
Filter: form.Filter, Filter: form.Filter,
AdminFilter: form.AdminFilter,
AttributeName: form.AttributeName, AttributeName: form.AttributeName,
AttributeSurname: form.AttributeSurname, AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail, AttributeMail: form.AttributeMail,
@ -160,6 +161,7 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
AttributeSurname: form.AttributeSurname, AttributeSurname: form.AttributeSurname,
AttributeMail: form.AttributeMail, AttributeMail: form.AttributeMail,
Filter: form.Filter, Filter: form.Filter,
AdminFilter: form.AdminFilter,
Enabled: true, Enabled: true,
}, },
} }

View file

@ -59,6 +59,10 @@
<label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.Source.LDAP.Filter}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.Source.LDAP.Filter}}" />
</div> </div>
<div class="field">
<label class="req" for="filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminFilter}}ipt-error{{end}}" id="admin_filter" name="admin_filter" value="{{.Source.LDAP.AdminFilter}}" />
</div>
<div class="field"> <div class="field">
<label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label> <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.Source.LDAP.AttributeName}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.Source.LDAP.AttributeName}}" />

View file

@ -55,6 +55,10 @@
<label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label> <label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.filter}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_Filter}}ipt-error{{end}}" id="filter" name="filter" value="{{.filter}}" />
</div> </div>
<div class="field">
<label class="req" for="filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AdminFilter}}ipt-error{{end}}" id="admin_filter" name="admin_filter" value="{{.admin_filter}}" />
</div>
<div class="field"> <div class="field">
<label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label> <label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_AttributeName}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.attribute_name}}" /> <input class="ipt ipt-large ipt-radius {{if .Err_AttributeName}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.attribute_name}}" />