| @@ -30,7 +30,7 @@ func LoginUserLdap(name, passwd string) (*User, error) { | |||
| Email: mail} | |||
| _, err := RegisterUser(&user) | |||
| if err != nil { | |||
| log.Debug("LDAP local user %s fond (%s) ", name, err) | |||
| log.Debug("LDAP local user %s found (%s) ", name, err) | |||
| } | |||
| // simulate local user login | |||
| localUser, err2 := GetUserByName(user.Name) | |||
| @@ -1,9 +1,12 @@ | |||
| package models | |||
| import | |||
| import ( | |||
| "encoding/json" | |||
| "time" | |||
| // Login types. | |||
| "github.com/go-xorm/core" | |||
| "github.com/go-xorm/core" | |||
| "github.com/gogits/gogs/modules/auth/ldap" | |||
| ) | |||
| /*const ( | |||
| LT_PLAIN = iota + 1 | |||
| @@ -14,20 +17,54 @@ import | |||
| var _ core.Conversion = &LDAPConfig{} | |||
| type LDAPConfig struct { | |||
| ldap.Ldapsource | |||
| } | |||
| // implement | |||
| func (cfg *LDAPConfig) FromDB(bs []byte) error { | |||
| return nil | |||
| return json.Unmarshal(bs, &cfg.Ldapsource) | |||
| } | |||
| func (cfg *LDAPConfig) ToDB() ([]byte, error) { | |||
| return nil, nil | |||
| return json.Marshal(cfg.Ldapsource) | |||
| } | |||
| type LoginSource struct { | |||
| Id int64 | |||
| Type int | |||
| Name string | |||
| Cfg LDAPConfig | |||
| Id int64 | |||
| Type int | |||
| Name string | |||
| IsActived bool | |||
| Cfg core.Conversion `xorm:"TEXT"` | |||
| Created time.Time `xorm:"created"` | |||
| Updated time.Time `xorm:"updated"` | |||
| } | |||
| func GetAuths() ([]*LoginSource, error) { | |||
| var auths = make([]*LoginSource, 0) | |||
| err := orm.Find(&auths) | |||
| return auths, err | |||
| } | |||
| func AddLDAPSource(name string, cfg *LDAPConfig) error { | |||
| _, err := orm.Insert(&LoginSource{Type: LT_LDAP, | |||
| Name: name, | |||
| IsActived: true, | |||
| Cfg: cfg, | |||
| }) | |||
| return err | |||
| } | |||
| func UpdateLDAPSource(id int64, name string, cfg *LDAPConfig) error { | |||
| _, err := orm.AllCols().Id(id).Update(&LoginSource{ | |||
| Id: id, | |||
| Type: LT_LDAP, | |||
| Name: name, | |||
| Cfg: cfg, | |||
| }) | |||
| return err | |||
| } | |||
| func DelLoginSource(id int64) error { | |||
| _, err := orm.Id(id).Delete(&LoginSource{}) | |||
| return err | |||
| } | |||
| @@ -34,7 +34,7 @@ var ( | |||
| func init() { | |||
| tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch), | |||
| new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow), | |||
| new(Mirror), new(Release)) | |||
| new(Mirror), new(Release), new(LoginSource)) | |||
| } | |||
| func LoadModelsConfig() { | |||
| @@ -0,0 +1,13 @@ | |||
| package auth | |||
| type AuthenticationForm struct { | |||
| Type int `form:"type"` | |||
| Name string `form:"name" binding:"MaxSize(50)"` | |||
| Domain string `form:"domain"` | |||
| Host string `form:"host"` | |||
| Port int `form:"port"` | |||
| BaseDN string `form:"base_dn"` | |||
| Attributes string `form:"attributes"` | |||
| Filter string `form:"filter"` | |||
| MsAdSA string `form:"ms_ad_sa"` | |||
| } | |||
| @@ -8,12 +8,13 @@ package ldap | |||
| import ( | |||
| "fmt" | |||
| "github.com/gogits/gogs/modules/log" | |||
| goldap "github.com/juju2013/goldap" | |||
| ) | |||
| // Basic LDAP authentication service | |||
| type ldapsource struct { | |||
| type Ldapsource struct { | |||
| Name string // canonical name (ie. corporate.ad) | |||
| Host string // LDAP host | |||
| Port int // port number | |||
| @@ -26,12 +27,12 @@ type ldapsource struct { | |||
| //Global LDAP directory pool | |||
| var ( | |||
| Authensource []ldapsource | |||
| Authensource []Ldapsource | |||
| ) | |||
| // Add a new source (LDAP directory) to the global pool | |||
| func AddSource(name string, host string, port int, basedn string, attributes string, filter string, msadsaformat string) { | |||
| ldaphost := ldapsource{name, host, port, basedn, attributes, filter, msadsaformat, true} | |||
| ldaphost := Ldapsource{name, host, port, basedn, attributes, filter, msadsaformat, true} | |||
| Authensource = append(Authensource, ldaphost) | |||
| } | |||
| @@ -50,7 +51,7 @@ func LoginUser(name, passwd string) (a string, r bool) { | |||
| } | |||
| // searchEntry : search an LDAP source if an entry (name, passwd) is valide and in the specific filter | |||
| func (ls ldapsource) searchEntry(name, passwd string) (string, bool) { | |||
| func (ls Ldapsource) searchEntry(name, passwd string) (string, bool) { | |||
| l, err := goldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port)) | |||
| if err != nil { | |||
| log.Debug("LDAP Connect error, disabled source %s", ls.Host) | |||
| @@ -120,6 +120,19 @@ func Users(ctx *middleware.Context) { | |||
| ctx.HTML(200, "admin/users") | |||
| } | |||
| func Auths(ctx *middleware.Context) { | |||
| ctx.Data["Title"] = "Auth Sources" | |||
| ctx.Data["PageIsAuths"] = true | |||
| var err error | |||
| ctx.Data["Sources"], err = models.GetAuths() | |||
| if err != nil { | |||
| ctx.Handle(200, "admin.Auths", err) | |||
| return | |||
| } | |||
| ctx.HTML(200, "admin/auths") | |||
| } | |||
| func Repositories(ctx *middleware.Context) { | |||
| ctx.Data["Title"] = "Repository Management" | |||
| ctx.Data["PageIsRepos"] = true | |||
| @@ -0,0 +1,62 @@ | |||
| package admin | |||
| import ( | |||
| "strings" | |||
| "github.com/gogits/gogs/models" | |||
| "github.com/gogits/gogs/modules/auth" | |||
| "github.com/gogits/gogs/modules/auth/ldap" | |||
| "github.com/gogits/gogs/modules/middleware" | |||
| "github.com/gpmgo/gopm/log" | |||
| ) | |||
| func NewAuthSource(ctx *middleware.Context) { | |||
| ctx.Data["Title"] = "New Authentication" | |||
| ctx.Data["PageIsAuths"] = true | |||
| ctx.HTML(200, "admin/auths/new") | |||
| } | |||
| func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) { | |||
| ctx.Data["Title"] = "New Authentication" | |||
| ctx.Data["PageIsAuths"] = true | |||
| if ctx.HasError() { | |||
| ctx.HTML(200, "admin/auths/new") | |||
| return | |||
| } | |||
| u := &models.LDAPConfig{ | |||
| Ldapsource: ldap.Ldapsource{ | |||
| Host: form.Host, | |||
| Port: form.Port, | |||
| BaseDN: form.BaseDN, | |||
| Attributes: form.Attributes, | |||
| Filter: form.Filter, | |||
| MsAdSAFormat: form.MsAdSA, | |||
| Enabled: true, | |||
| Name: form.Name, | |||
| }, | |||
| } | |||
| if err := models.AddLDAPSource(form.Name, u); err != nil { | |||
| switch err { | |||
| default: | |||
| ctx.Handle(500, "admin.auths.NewAuth", err) | |||
| } | |||
| return | |||
| } | |||
| log.Trace("%s Authentication created by admin(%s): %s", ctx.Req.RequestURI, | |||
| ctx.User.LowerName, strings.ToLower(form.Name)) | |||
| ctx.Redirect("/admin/auths") | |||
| } | |||
| func EditAuthSource(ctx *middleware.Context) { | |||
| } | |||
| func EditAuthSourcePost(ctx *middleware.Context) { | |||
| } | |||
| func DeleteAuthSource(ctx *middleware.Context) { | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="body" class="container" data-page="admin"> | |||
| {{template "admin/nav" .}} | |||
| <div id="admin-container" class="col-md-10"> | |||
| <div class="panel panel-default"> | |||
| <div class="panel-heading"> | |||
| Authentication Management | |||
| </div> | |||
| <div class="panel-body"> | |||
| <a href="/admin/auths/new" class="btn btn-primary">New Auth Source</a> | |||
| <table class="table table-striped"> | |||
| <thead> | |||
| <tr> | |||
| <th>Id</th> | |||
| <th>Name</th> | |||
| <th>Type</th> | |||
| <th>Actived</th> | |||
| <th>Updated</th> | |||
| <th>Created</th> | |||
| <th>Operation</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {{range .Sources}} | |||
| <tr> | |||
| <td>{{.Id}}</td> | |||
| <td><a href="/admin/auths/{{.Id}}">{{.Name}}</a></td> | |||
| <td>{{.Type}}</td> | |||
| <td>{{.Actived}}</td> | |||
| <td>{{DateFormat .Updated "M d, Y"}}</td> | |||
| <td>{{DateFormat .Created "M d, Y"}}</td> | |||
| <td><a href="/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td> | |||
| </tr> | |||
| {{end}} | |||
| </tbody> | |||
| </table> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -0,0 +1,93 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="body" class="container" data-page="admin"> | |||
| {{template "admin/nav" .}} | |||
| <div id="admin-container" class="col-md-9"> | |||
| <div class="panel panel-default"> | |||
| <div class="panel-heading"> | |||
| New Authentication | |||
| </div> | |||
| <div class="panel-body"> | |||
| <br/> | |||
| <form action="/admin/auths/new" method="post" class="form-horizontal"> | |||
| {{.CsrfTokenHtml}} | |||
| {{template "base/alert" .}} | |||
| <div class="form-group"> | |||
| <label class="col-md-3 control-label">Auth Type: </label> | |||
| <div class="col-md-7"> | |||
| <select class="form-control"> | |||
| <option value=2>LDAP</option> | |||
| <option value=3>SMTP</option> | |||
| </select> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Name: </label> | |||
| <div class="col-md-7"> | |||
| <input name="name" class="form-control" placeholder="Type account's username" value="{{.username}}" required="required"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Domain: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Host: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Port: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Base DN: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Search Attributes: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Search Filter: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <label class="col-md-3 control-label">Ms Ad SA: </label> | |||
| <div class="col-md-7"> | |||
| <input name="domain" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | |||
| </div> | |||
| </div> | |||
| <hr/> | |||
| <div class="form-group"> | |||
| <div class="col-md-offset-3 col-md-7"> | |||
| <button type="submit" class="btn btn-lg btn-primary">Create new authentication</button> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -4,5 +4,6 @@ | |||
| <li class="list-group-item{{if .PageIsUsers}} active{{end}}"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li> | |||
| <li class="list-group-item{{if .PageIsRepos}} active{{end}}"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li> | |||
| <li class="list-group-item{{if .PageIsConfig}} active{{end}}"><a href="/admin/config"><i class="fa fa-cogs fa-lg"></i> Configuration</a></li> | |||
| <li class="list-group-item{{if .PageIsAuths}} active{{end}}"><a href="/admin/auths"><i class="fa fa-cogs fa-lg"></i> Authentication</a></li> | |||
| </ul> | |||
| </div> | |||
| @@ -130,6 +130,7 @@ func runWeb(*cli.Context) { | |||
| r.Get("/users", admin.Users) | |||
| r.Get("/repos", admin.Repositories) | |||
| r.Get("/config", admin.Config) | |||
| r.Get("/auths", admin.Auths) | |||
| }, adminReq) | |||
| m.Group("/admin/users", func(r martini.Router) { | |||
| r.Get("/new", admin.NewUser) | |||
| @@ -139,6 +140,14 @@ func runWeb(*cli.Context) { | |||
| r.Get("/:userid/delete", admin.DeleteUser) | |||
| }, adminReq) | |||
| m.Group("/admin/auths", func(r martini.Router) { | |||
| r.Get("/new", admin.NewAuthSource) | |||
| r.Post("/new", bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost) | |||
| r.Get("/:authid", admin.EditAuthSource) | |||
| r.Post("/:authid" /*, bindIgnErr(auth.AdminEditUserForm{})*/, admin.EditAuthSourcePost) | |||
| r.Get("/:authid/delete", admin.DeleteAuthSource) | |||
| }, adminReq) | |||
| if martini.Env == martini.Dev { | |||
| m.Get("/template/**", dev.TemplatePreview) | |||
| } | |||