From 8bab21d795a6af7c424e9f8f72d613863cf34a70 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 26 Apr 2014 14:21:04 +0800
Subject: [PATCH 1/3] add login.go

---
 models/login.go | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 models/login.go

diff --git a/models/login.go b/models/login.go
new file mode 100644
index 0000000000..e8dbfc2725
--- /dev/null
+++ b/models/login.go
@@ -0,0 +1,33 @@
+package models
+
+import
+
+// Login types.
+"github.com/go-xorm/core"
+
+/*const (
+	LT_PLAIN = iota + 1
+	LT_LDAP
+	LT_SMTP
+)*/
+
+var _ core.Conversion = &LDAPConfig{}
+
+type LDAPConfig struct {
+}
+
+// implement
+func (cfg *LDAPConfig) FromDB(bs []byte) error {
+	return nil
+}
+
+func (cfg *LDAPConfig) ToDB() ([]byte, error) {
+	return nil, nil
+}
+
+type LoginSource struct {
+	Id   int64
+	Type int
+	Name string
+	Cfg  LDAPConfig
+}

From 79ea34e70ebe989f1a5f8fbd71cfe3109c6f8a58 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 3 May 2014 10:48:14 +0800
Subject: [PATCH 2/3] ldap support

---
 models/ldap.go                 |  2 +-
 models/login.go                | 55 ++++++++++++++++----
 models/models.go               |  2 +-
 modules/auth/authentication.go | 13 +++++
 modules/auth/ldap/ldap.go      |  9 ++--
 routers/admin/admin.go         | 13 +++++
 routers/admin/auths.go         | 62 +++++++++++++++++++++++
 templates/admin/auths.tmpl     | 43 ++++++++++++++++
 templates/admin/auths/new.tmpl | 93 ++++++++++++++++++++++++++++++++++
 templates/admin/nav.tmpl       |  1 +
 web.go                         |  9 ++++
 11 files changed, 287 insertions(+), 15 deletions(-)
 create mode 100644 modules/auth/authentication.go
 create mode 100644 routers/admin/auths.go
 create mode 100644 templates/admin/auths.tmpl
 create mode 100644 templates/admin/auths/new.tmpl

diff --git a/models/ldap.go b/models/ldap.go
index cc9058765f..1da5b87540 100644
--- a/models/ldap.go
+++ b/models/ldap.go
@@ -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)
diff --git a/models/login.go b/models/login.go
index e8dbfc2725..6d9e54943f 100644
--- a/models/login.go
+++ b/models/login.go
@@ -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
 }
diff --git a/models/models.go b/models/models.go
index 8e8835ab51..3bce764963 100644
--- a/models/models.go
+++ b/models/models.go
@@ -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() {
diff --git a/modules/auth/authentication.go b/modules/auth/authentication.go
new file mode 100644
index 0000000000..5c179f0fc0
--- /dev/null
+++ b/modules/auth/authentication.go
@@ -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"`
+}
diff --git a/modules/auth/ldap/ldap.go b/modules/auth/ldap/ldap.go
index 29773cda5c..8578e38a4d 100644
--- a/modules/auth/ldap/ldap.go
+++ b/modules/auth/ldap/ldap.go
@@ -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)
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index d0f737e645..bd7cc98f64 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -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
diff --git a/routers/admin/auths.go b/routers/admin/auths.go
new file mode 100644
index 0000000000..69d38db5d4
--- /dev/null
+++ b/routers/admin/auths.go
@@ -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) {
+}
diff --git a/templates/admin/auths.tmpl b/templates/admin/auths.tmpl
new file mode 100644
index 0000000000..813e24ad0c
--- /dev/null
+++ b/templates/admin/auths.tmpl
@@ -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" .}}
\ No newline at end of file
diff --git a/templates/admin/auths/new.tmpl b/templates/admin/auths/new.tmpl
new file mode 100644
index 0000000000..346555ea9c
--- /dev/null
+++ b/templates/admin/auths/new.tmpl
@@ -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" .}}
\ No newline at end of file
diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl
index 33ecfae5e3..b9542228bc 100644
--- a/templates/admin/nav.tmpl
+++ b/templates/admin/nav.tmpl
@@ -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>
\ No newline at end of file
diff --git a/web.go b/web.go
index 23fa10796c..32b45c00a2 100644
--- a/web.go
+++ b/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)
 	}

From 1652dd5068f2f3ae1851bc2321832c88af85d570 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Mon, 5 May 2014 16:40:25 +0800
Subject: [PATCH 3/3] basic authentications

---
 models/login.go                 |  73 ++++++++++++++++++----
 models/user.go                  |   7 +--
 modules/auth/admin.go           |  13 ++--
 modules/auth/auth.go            |   1 +
 modules/auth/authentication.go  |   2 +
 routers/admin/auths.go          |  91 ++++++++++++++++++++++++++-
 routers/admin/user.go           |  33 ++++++++--
 templates/admin/auths.tmpl      |   6 +-
 templates/admin/auths/edit.tmpl | 107 ++++++++++++++++++++++++++++++++
 templates/admin/auths/new.tmpl  |  23 +++----
 templates/admin/users/edit.tmpl |  12 ++++
 templates/admin/users/new.tmpl  |  11 ++++
 web.go                          |   4 +-
 13 files changed, 334 insertions(+), 49 deletions(-)
 create mode 100644 templates/admin/auths/edit.tmpl

diff --git a/models/login.go b/models/login.go
index 6d9e54943f..d5905eb36b 100644
--- a/models/login.go
+++ b/models/login.go
@@ -2,17 +2,31 @@ package models
 
 import (
 	"encoding/json"
+	"errors"
 	"time"
 
 	"github.com/go-xorm/core"
+	"github.com/go-xorm/xorm"
 	"github.com/gogits/gogs/modules/auth/ldap"
 )
 
-/*const (
+// Login types.
+const (
 	LT_PLAIN = iota + 1
 	LT_LDAP
 	LT_SMTP
-)*/
+)
+
+var (
+	ErrAuthenticationAlreadyExist = errors.New("Authentication already exist")
+	ErrAuthenticationNotExist     = errors.New("Authentication is not exist")
+	ErrAuthenticationUserUsed     = errors.New("Authentication has been used by some users")
+)
+
+var LoginTypes = map[int]string{
+	LT_LDAP: "LDAP",
+	LT_SMTP: "SMTP",
+}
 
 var _ core.Conversion = &LDAPConfig{}
 
@@ -32,19 +46,50 @@ func (cfg *LDAPConfig) ToDB() ([]byte, error) {
 type LoginSource struct {
 	Id        int64
 	Type      int
-	Name      string
-	IsActived bool
+	Name      string          `xorm:"unique"`
+	IsActived bool            `xorm:"not null default false"`
 	Cfg       core.Conversion `xorm:"TEXT"`
 	Created   time.Time       `xorm:"created"`
 	Updated   time.Time       `xorm:"updated"`
 }
 
+func (source *LoginSource) TypeString() string {
+	return LoginTypes[source.Type]
+}
+
+func (source *LoginSource) LDAP() *LDAPConfig {
+	return source.Cfg.(*LDAPConfig)
+}
+
+// for xorm callback
+func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
+	if colName == "type" {
+		ty := (*val).(int64)
+		switch ty {
+		case LT_LDAP:
+			source.Cfg = new(LDAPConfig)
+		}
+	}
+}
+
 func GetAuths() ([]*LoginSource, error) {
 	var auths = make([]*LoginSource, 0)
 	err := orm.Find(&auths)
 	return auths, err
 }
 
+func GetLoginSourceById(id int64) (*LoginSource, error) {
+	source := new(LoginSource)
+	has, err := orm.Id(id).Get(source)
+	if err != nil {
+		return nil, err
+	}
+	if !has {
+		return nil, ErrAuthenticationNotExist
+	}
+	return source, nil
+}
+
 func AddLDAPSource(name string, cfg *LDAPConfig) error {
 	_, err := orm.Insert(&LoginSource{Type: LT_LDAP,
 		Name:      name,
@@ -54,17 +99,19 @@ func AddLDAPSource(name string, cfg *LDAPConfig) error {
 	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,
-	})
+func UpdateLDAPSource(source *LoginSource) error {
+	_, err := orm.AllCols().Id(source.Id).Update(source)
 	return err
 }
 
-func DelLoginSource(id int64) error {
-	_, err := orm.Id(id).Delete(&LoginSource{})
+func DelLoginSource(source *LoginSource) error {
+	cnt, err := orm.Count(&User{LoginSource: source.Id})
+	if err != nil {
+		return err
+	}
+	if cnt > 0 {
+		return ErrAuthenticationUserUsed
+	}
+	_, err = orm.Id(source.Id).Delete(&LoginSource{})
 	return err
 }
diff --git a/models/user.go b/models/user.go
index df1eb985c2..3372d75497 100644
--- a/models/user.go
+++ b/models/user.go
@@ -26,12 +26,6 @@ const (
 	UT_ORGANIZATION
 )
 
-// Login types.
-const (
-	LT_PLAIN = iota + 1
-	LT_LDAP
-)
-
 var (
 	ErrUserOwnRepos     = errors.New("User still have ownership of repositories")
 	ErrUserAlreadyExist = errors.New("User already exist")
@@ -49,6 +43,7 @@ type User struct {
 	Email         string `xorm:"unique not null"`
 	Passwd        string `xorm:"not null"`
 	LoginType     int
+	LoginSource   int64 `xorm:"not null default 0"`
 	Type          int
 	NumFollowers  int
 	NumFollowings int
diff --git a/modules/auth/admin.go b/modules/auth/admin.go
index 877af19af3..e2dc0fd218 100644
--- a/modules/auth/admin.go
+++ b/modules/auth/admin.go
@@ -15,12 +15,13 @@ import (
 )
 
 type AdminEditUserForm struct {
-	Email    string `form:"email" binding:"Required;Email;MaxSize(50)"`
-	Website  string `form:"website" binding:"MaxSize(50)"`
-	Location string `form:"location" binding:"MaxSize(50)"`
-	Avatar   string `form:"avatar" binding:"Required;Email;MaxSize(50)"`
-	Active   string `form:"active"`
-	Admin    string `form:"admin"`
+	Email     string `form:"email" binding:"Required;Email;MaxSize(50)"`
+	Website   string `form:"website" binding:"MaxSize(50)"`
+	Location  string `form:"location" binding:"MaxSize(50)"`
+	Avatar    string `form:"avatar" binding:"Required;Email;MaxSize(50)"`
+	Active    string `form:"active"`
+	Admin     string `form:"admin"`
+	LoginType int    `form:"login_type"`
 }
 
 func (f *AdminEditUserForm) Name(field string) string {
diff --git a/modules/auth/auth.go b/modules/auth/auth.go
index 350ef4fcbf..49ace507b7 100644
--- a/modules/auth/auth.go
+++ b/modules/auth/auth.go
@@ -25,6 +25,7 @@ type RegisterForm struct {
 	Email        string `form:"email" binding:"Required;Email;MaxSize(50)"`
 	Password     string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
 	RetypePasswd string `form:"retypepasswd"`
+	LoginType    string `form:"logintype"`
 }
 
 func (f *RegisterForm) Name(field string) string {
diff --git a/modules/auth/authentication.go b/modules/auth/authentication.go
index 5c179f0fc0..d9c61b9d79 100644
--- a/modules/auth/authentication.go
+++ b/modules/auth/authentication.go
@@ -1,6 +1,7 @@
 package auth
 
 type AuthenticationForm struct {
+	Id         int64  `form:"id"`
 	Type       int    `form:"type"`
 	Name       string `form:"name" binding:"MaxSize(50)"`
 	Domain     string `form:"domain"`
@@ -10,4 +11,5 @@ type AuthenticationForm struct {
 	Attributes string `form:"attributes"`
 	Filter     string `form:"filter"`
 	MsAdSA     string `form:"ms_ad_sa"`
+	IsActived  bool   `form:"is_actived"`
 }
diff --git a/routers/admin/auths.go b/routers/admin/auths.go
index 69d38db5d4..892413049e 100644
--- a/routers/admin/auths.go
+++ b/routers/admin/auths.go
@@ -3,9 +3,11 @@ package admin
 import (
 	"strings"
 
+	"github.com/go-martini/martini"
 	"github.com/gogits/gogs/models"
 	"github.com/gogits/gogs/modules/auth"
 	"github.com/gogits/gogs/modules/auth/ldap"
+	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/middleware"
 	"github.com/gpmgo/gopm/log"
 )
@@ -13,6 +15,7 @@ import (
 func NewAuthSource(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Authentication"
 	ctx.Data["PageIsAuths"] = true
+	ctx.Data["LoginTypes"] = models.LoginTypes
 	ctx.HTML(200, "admin/auths/new")
 }
 
@@ -52,11 +55,93 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
 	ctx.Redirect("/admin/auths")
 }
 
-func EditAuthSource(ctx *middleware.Context) {
+func EditAuthSource(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Edit Authentication"
+	ctx.Data["PageIsAuths"] = true
+	id, err := base.StrTo(params["authid"]).Int64()
+	if err != nil {
+		ctx.Handle(404, "admin.auths.EditAuthSource", err)
+		return
+	}
+	u, err := models.GetLoginSourceById(id)
+	if err != nil {
+		ctx.Handle(500, "admin.user.EditUser", err)
+		return
+	}
+	ctx.Data["Source"] = u
+	ctx.Data["LoginTypes"] = models.LoginTypes
+	ctx.HTML(200, "admin/auths/edit")
 }
 
-func EditAuthSourcePost(ctx *middleware.Context) {
+func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
+	ctx.Data["Title"] = "Edit Authentication"
+	ctx.Data["PageIsAuths"] = true
+
+	if ctx.HasError() {
+		ctx.HTML(200, "admin/auths/edit")
+		return
+	}
+
+	u := models.LoginSource{
+		Name:      form.Name,
+		IsActived: form.IsActived,
+		Type:      models.LT_LDAP,
+		Cfg: &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.UpdateLDAPSource(&u); err != nil {
+		switch err {
+		default:
+			ctx.Handle(500, "admin.auths.EditAuth", err)
+		}
+		return
+	}
+
+	log.Trace("%s Authentication changed by admin(%s): %s", ctx.Req.RequestURI,
+		ctx.User.LowerName, strings.ToLower(form.Name))
+
+	ctx.Redirect("/admin/auths")
 }
 
-func DeleteAuthSource(ctx *middleware.Context) {
+func DeleteAuthSource(ctx *middleware.Context, params martini.Params) {
+	ctx.Data["Title"] = "Delete Authentication"
+	ctx.Data["PageIsAuths"] = true
+
+	id, err := base.StrTo(params["authid"]).Int64()
+	if err != nil {
+		ctx.Handle(404, "admin.auths.DeleteAuth", err)
+		return
+	}
+
+	a, err := models.GetLoginSourceById(id)
+	if err != nil {
+		ctx.Handle(500, "admin.auths.DeleteAuth", err)
+		return
+	}
+
+	if err = models.DelLoginSource(a); err != nil {
+		switch err {
+		case models.ErrAuthenticationUserUsed:
+			ctx.Flash.Error("This authentication still has used by some users, you should move them and then delete again.")
+			ctx.Redirect("/admin/auths/" + params["authid"])
+		default:
+			ctx.Handle(500, "admin.auths.DeleteAuth", err)
+		}
+		return
+	}
+	log.Trace("%s Authentication deleted by admin(%s): %s", ctx.Req.RequestURI,
+		ctx.User.LowerName, ctx.User.LowerName)
+
+	ctx.Redirect("/admin/auths")
 }
diff --git a/routers/admin/user.go b/routers/admin/user.go
index fee692202e..14c17e9756 100644
--- a/routers/admin/user.go
+++ b/routers/admin/user.go
@@ -5,6 +5,8 @@
 package admin
 
 import (
+	"fmt"
+	"strconv"
 	"strings"
 
 	"github.com/go-martini/martini"
@@ -19,6 +21,12 @@ import (
 func NewUser(ctx *middleware.Context) {
 	ctx.Data["Title"] = "New Account"
 	ctx.Data["PageIsUsers"] = true
+	auths, err := models.GetAuths()
+	if err != nil {
+		ctx.Handle(500, "admin.user.NewUser", err)
+		return
+	}
+	ctx.Data["LoginSources"] = auths
 	ctx.HTML(200, "admin/users/new")
 }
 
@@ -40,10 +48,18 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) {
 	}
 
 	u := &models.User{
-		Name:     form.UserName,
-		Email:    form.Email,
-		Passwd:   form.Password,
-		IsActive: true,
+		Name:      form.UserName,
+		Email:     form.Email,
+		Passwd:    form.Password,
+		IsActive:  true,
+		LoginType: models.LT_PLAIN,
+	}
+
+	if len(form.LoginType) > 0 {
+		fields := strings.Split(form.LoginType, "-")
+		u.LoginType, _ = strconv.Atoi(fields[0])
+		u.LoginSource, _ = strconv.ParseInt(fields[1], 10, 64)
+		fmt.Println(u.LoginSource)
 	}
 
 	var err error
@@ -84,6 +100,12 @@ func EditUser(ctx *middleware.Context, params martini.Params) {
 	}
 
 	ctx.Data["User"] = u
+	auths, err := models.GetAuths()
+	if err != nil {
+		ctx.Handle(500, "admin.user.NewUser", err)
+		return
+	}
+	ctx.Data["LoginSources"] = auths
 	ctx.HTML(200, "admin/users/edit")
 }
 
@@ -110,6 +132,7 @@ func EditUserPost(ctx *middleware.Context, params martini.Params, form auth.Admi
 	u.AvatarEmail = form.Avatar
 	u.IsActive = form.Active == "on"
 	u.IsAdmin = form.Admin == "on"
+	u.LoginType = form.LoginType
 	if err := models.UpdateUser(u); err != nil {
 		ctx.Handle(500, "admin.user.EditUser", err)
 		return
@@ -126,7 +149,7 @@ func DeleteUser(ctx *middleware.Context, params martini.Params) {
 	ctx.Data["Title"] = "Delete Account"
 	ctx.Data["PageIsUsers"] = true
 
-	log.Info("delete")
+	//log.Info("delete")
 	uid, err := base.StrTo(params["userid"]).Int()
 	if err != nil {
 		ctx.Handle(404, "admin.user.EditUser", err)
diff --git a/templates/admin/auths.tmpl b/templates/admin/auths.tmpl
index 813e24ad0c..87baeafd62 100644
--- a/templates/admin/auths.tmpl
+++ b/templates/admin/auths.tmpl
@@ -27,11 +27,11 @@
                         <tr>
                             <td>{{.Id}}</td>
                             <td><a href="/admin/auths/{{.Id}}">{{.Name}}</a></td>
-                            <td>{{.Type}}</td>
-                            <td>{{.Actived}}</td>
+                            <td>{{.TypeString}}</td>
+                            <td><i class="fa fa{{if .IsActived}}-check{{end}}-square-o"></i></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>
+                            <td><a href="/admin/auths/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td>
                         </tr>
                         {{end}}
                     </tbody>
diff --git a/templates/admin/auths/edit.tmpl b/templates/admin/auths/edit.tmpl
new file mode 100644
index 0000000000..1a2548fbeb
--- /dev/null
+++ b/templates/admin/auths/edit.tmpl
@@ -0,0 +1,107 @@
+{{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">
+                Edit Authentication
+            </div>
+
+            <div class="panel-body">
+                <br/>
+                <form action="/admin/auths/{{.Source.Id}}" method="post" class="form-horizontal">
+                    {{.CsrfTokenHtml}}
+                    {{template "base/alert" .}}
+                    <input type="hidden" value="{{.Source.Id}}" name="id"/>
+                    <div class="form-group">
+                    <label class="col-md-3 control-label">Auth Type: </label>
+                    <div class="col-md-7">
+                    <select class="form-control">
+                    {{$type := .Source.Type}}
+  {{range $key, $val := .LoginTypes}}
+                    <option value="{{$key}}" {{if eq $key $type}}selected{{end}}>{{$val}}</option>
+                    {{end}}
+</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="{{.Source.Name}}" 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="{{.Source.LDAP.Name}}" 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="host" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.Host}}" 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="port" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.Port}}" 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="base_dn" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.BaseDN}}" 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="attributes" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.Attributes}}" 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="filter" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.Filter}}" 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="ms_ad_sa" class="form-control" placeholder="Type account's e-mail address" value="{{.Source.LDAP.MsAdSAFormat}}" required="required" title="Email is not valid">
+                        </div>
+                    </div>
+                    
+                    <div class="form-group">
+                        <div class="col-md-7 col-md-offset-3">
+                            <div class="checkbox">
+                                <label>
+                                    <input type="checkbox" name="is_actived" {{if .Source.IsActived}}checked{{end}}>
+                                    <strong>This authentication has activated.</strong>
+                                </label>
+                            </div>
+                        </div>
+                    </div>
+                    <hr/>
+                    <div class="form-group">
+                        <div class="col-md-offset-3 col-md-6">
+                            <button type="submit" class="btn btn-lg btn-primary btn-block">Update authentication config</button>
+                            <a type="button" href="/admin/auths/{{.Source.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this authentication</a>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+
+    </div>
+</div>
+{{template "base/footer" .}}
\ No newline at end of file
diff --git a/templates/admin/auths/new.tmpl b/templates/admin/auths/new.tmpl
index 346555ea9c..a5da93bd2a 100644
--- a/templates/admin/auths/new.tmpl
+++ b/templates/admin/auths/new.tmpl
@@ -17,64 +17,65 @@
 				    <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>
+				    {{range $key, $val := .LoginTypes}}
+  					<option value="{{$key}}">{{$val}}</option>
+  					{{end}}
+					</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">
+							<input name="name" class="form-control" placeholder="Authentication's name" 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">
+							<input name="domain" class="form-control" placeholder="Domain name" value="{{.domain}}" 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">
+							<input name="host" 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">
+							<input name="port" 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">
+							<input name="base_dn" 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">
+							<input name="attributes" 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">
+							<input name="filter" 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">
+							<input name="ms_ad_sa" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid">
 						</div>
 					</div>
 					
diff --git a/templates/admin/users/edit.tmpl b/templates/admin/users/edit.tmpl
index da9a67cfae..9c9c36a28c 100644
--- a/templates/admin/users/edit.tmpl
+++ b/templates/admin/users/edit.tmpl
@@ -14,6 +14,18 @@
 				    {{.CsrfTokenHtml}}
 				    {{template "base/alert" .}}
                 	<input type="hidden" value="{{.User.Id}}" name="userId"/>
+	<div class="form-group">
+				    <label class="col-md-3 control-label">Auth Source: </label>
+				    <div class="col-md-7">
+				    <select name="logintype" class="form-control">
+				    <option value="0-0"{{if eq 0 .User.LoginSource}} selected{{end}}>Local</option>
+				    {{$tp := .User.LoginSource}}
+				    {{range $key, $val := .LoginSources}}
+  					<option value="{{$val.Type}}-{{$val.Id}}"{{if eq $val.Id $tp}} selected{{end}}>{{$val.Name}}</option>
+  					{{end}}
+					</select>
+	</div>
+	</div>
 					<div class="form-group">
 						<label class="col-md-3 control-label">Username: </label>
 						<label class="control-label">{{.User.Name}}</label>
diff --git a/templates/admin/users/new.tmpl b/templates/admin/users/new.tmpl
index 4c851e3144..c19cd53c0a 100644
--- a/templates/admin/users/new.tmpl
+++ b/templates/admin/users/new.tmpl
@@ -13,6 +13,17 @@
 				<form action="/admin/users/new" method="post" class="form-horizontal">
 					{{.CsrfTokenHtml}}
 				    {{template "base/alert" .}}
+				    <div class="form-group">
+				    <label class="col-md-3 control-label">Auth Source: </label>
+				    <div class="col-md-7">
+				    <select name="logintype" class="form-control">
+				    <option value="0-0">Local</option>
+				    {{range $key, $val := .LoginSources}}
+  					<option value="{{$val.Type}}-{{$val.Id}}">{{$val.Name}}</option>
+  					{{end}}
+					</select>
+	</div>
+	</div>
 					<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
 						<label class="col-md-3 control-label">Username: </label>
 						<div class="col-md-7">
diff --git a/web.go b/web.go
index 32b45c00a2..4222be9b13 100644
--- a/web.go
+++ b/web.go
@@ -144,7 +144,7 @@ func runWeb(*cli.Context) {
 		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.Post("/:authid", bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost)
 		r.Get("/:authid/delete", admin.DeleteAuthSource)
 	}, adminReq)
 
@@ -196,7 +196,7 @@ func runWeb(*cli.Context) {
 
 	protocol := base.Cfg.MustValue("server", "PROTOCOL", "http")
 	listenAddr := fmt.Sprintf("%s:%s",
-		base.Cfg.MustValue("server", "HTTP_ADDR"),
+		base.Cfg.MustValue("server", "HTTP_ADDR", "0.0.0.0"),
 		base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
 
 	if protocol == "http" {