mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-28 14:43:52 +03:00
ldap support
This commit is contained in:
parent
8bab21d795
commit
79ea34e70e
11 changed files with 287 additions and 15 deletions
|
@ -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() {
|
||||
|
|
13
modules/auth/authentication.go
Normal file
13
modules/auth/authentication.go
Normal file
|
@ -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
|
||||
|
|
62
routers/admin/auths.go
Normal file
62
routers/admin/auths.go
Normal file
|
@ -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) {
|
||||
}
|
43
templates/admin/auths.tmpl
Normal file
43
templates/admin/auths.tmpl
Normal file
|
@ -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" .}}
|
93
templates/admin/auths/new.tmpl
Normal file
93
templates/admin/auths/new.tmpl
Normal file
|
@ -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>
|
9
web.go
9
web.go
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue