Explorar o código

login_source: add default authentication switch (#5338)

* Add default Authentication Switch.

* adjust the code accroding to reviews

* #1. Remove redudant logic.
#2, Fix a bug in "Edit" panel.

* Remove unused logic

* Fix local authentication files are not flushed.

* refactor according to review.
haixunlu %!s(int64=5) %!d(string=hai) anos
pai
achega
68a6579852

+ 40 - 8
models/login_source.go

@@ -133,6 +133,7 @@ type LoginSource struct {
 	Type      LoginType
 	Name      string          `xorm:"UNIQUE"`
 	IsActived bool            `xorm:"NOT NULL DEFAULT false"`
+	IsDefault bool            `xorm:"DEFAULT false"`
 	Cfg       core.Conversion `xorm:"TEXT"`
 
 	Created     time.Time `xorm:"-" json:"-"`
@@ -257,7 +258,12 @@ func CreateLoginSource(source *LoginSource) error {
 	}
 
 	_, err = x.Insert(source)
-	return err
+	if err != nil {
+		return err
+	} else if source.IsDefault {
+		return ResetNonDefaultLoginSources(source)
+	}
+	return nil
 }
 
 // LoginSources returns all login sources defined.
@@ -291,23 +297,48 @@ func GetLoginSourceByID(id int64) (*LoginSource, error) {
 	return source, nil
 }
 
+// ResetNonDefaultLoginSources clean other default source flag
+func ResetNonDefaultLoginSources(source *LoginSource) error {
+	// update changes to DB
+	if _, err := x.NotIn("id", []int64{source.ID}).Cols("is_default").Update(&LoginSource{IsDefault: false}); err != nil {
+		return err
+	}
+	// write changes to local authentications
+	for i := range localLoginSources.sources {
+		if localLoginSources.sources[i].LocalFile != nil && localLoginSources.sources[i].ID != source.ID {
+			localLoginSources.sources[i].LocalFile.SetGeneral("is_default", "false")
+			if err := localLoginSources.sources[i].LocalFile.SetConfig(source.Cfg); err != nil {
+				return fmt.Errorf("LocalFile.SetConfig: %v", err)
+			} else if err = localLoginSources.sources[i].LocalFile.Save(); err != nil {
+				return fmt.Errorf("LocalFile.Save: %v", err)
+			}
+		}
+	}
+	// flush memory so that web page can show the same behaviors
+	localLoginSources.UpdateLoginSource(source)
+	return nil
+}
+
 // UpdateLoginSource updates information of login source to database or local file.
 func UpdateLoginSource(source *LoginSource) error {
 	if source.LocalFile == nil {
-		_, err := x.Id(source.ID).AllCols().Update(source)
-		return err
+		if _, err := x.Id(source.ID).AllCols().Update(source); err != nil {
+			return err
+		} else {
+			return ResetNonDefaultLoginSources(source)
+		}
+
 	}
 
 	source.LocalFile.SetGeneral("name", source.Name)
 	source.LocalFile.SetGeneral("is_activated", com.ToStr(source.IsActived))
+	source.LocalFile.SetGeneral("is_default", com.ToStr(source.IsDefault))
 	if err := source.LocalFile.SetConfig(source.Cfg); err != nil {
 		return fmt.Errorf("LocalFile.SetConfig: %v", err)
 	} else if err = source.LocalFile.Save(); err != nil {
 		return fmt.Errorf("LocalFile.Save: %v", err)
 	}
-
-	localLoginSources.UpdateLoginSource(source)
-	return nil
+	return ResetNonDefaultLoginSources(source)
 }
 
 func DeleteSource(source *LoginSource) error {
@@ -361,7 +392,6 @@ func (s *LocalLoginSources) ActivatedList() []*LoginSource {
 		if !s.sources[i].IsActived {
 			continue
 		}
-
 		source := &LoginSource{}
 		*source = *s.sources[i]
 		list = append(list, source)
@@ -394,7 +424,8 @@ func (s *LocalLoginSources) UpdateLoginSource(source *LoginSource) {
 	for i := range s.sources {
 		if s.sources[i].ID == source.ID {
 			*s.sources[i] = *source
-			break
+		} else if source.IsDefault {
+			s.sources[i].IsDefault = false
 		}
 	}
 }
@@ -429,6 +460,7 @@ func LoadAuthSources() {
 			ID:        s.Key("id").MustInt64(),
 			Name:      s.Key("name").String(),
 			IsActived: s.Key("is_activated").MustBool(),
+			IsDefault: s.Key("is_default").MustBool(),
 			LocalFile: &AuthSourceFile{
 				abspath: fpath,
 				file:    authSource,

+ 1 - 0
pkg/form/auth.go

@@ -32,6 +32,7 @@ type Authentication struct {
 	GroupMemberUID    string
 	UserUID           string
 	IsActive          bool
+	IsDefault         bool
 	SMTPAuth          string
 	SMTPHost          string
 	SMTPPort          int

+ 4 - 0
routes/admin/auths.go

@@ -69,6 +69,7 @@ func NewAuthSource(c *context.Context) {
 	c.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED]
 	c.Data["smtp_auth"] = "PLAIN"
 	c.Data["is_active"] = true
+	c.Data["is_default"] = true
 	c.Data["AuthSources"] = authSources
 	c.Data["SecurityProtocols"] = securityProtocols
 	c.Data["SMTPAuths"] = models.SMTPAuths
@@ -152,6 +153,7 @@ func NewAuthSourcePost(c *context.Context, f form.Authentication) {
 		Type:      models.LoginType(f.Type),
 		Name:      f.Name,
 		IsActived: f.IsActive,
+		IsDefault: f.IsDefault,
 		Cfg:       config,
 	}); err != nil {
 		if models.IsErrLoginSourceAlreadyExist(err) {
@@ -225,11 +227,13 @@ func EditAuthSourcePost(c *context.Context, f form.Authentication) {
 
 	source.Name = f.Name
 	source.IsActived = f.IsActive
+	source.IsDefault = f.IsDefault
 	source.Cfg = config
 	if err := models.UpdateLoginSource(source); err != nil {
 		c.ServerError("UpdateLoginSource", err)
 		return
 	}
+
 	log.Trace("Authentication changed by admin '%s': %d", c.User.Name, source.ID)
 
 	c.Flash.Success(c.Tr("admin.auths.update_success"))

+ 18 - 1
routes/user/auth.go

@@ -113,7 +113,15 @@ func Login(c *context.Context) {
 		return
 	}
 	c.Data["LoginSources"] = loginSources
-
+	for i := range loginSources {
+		if loginSources[i].IsDefault {
+			c.Data["DefaultSource"] = *loginSources[i]
+			c.Data["login_source"] = loginSources[i].ID
+			newLoginSources := append(loginSources[:i], loginSources[i+1:]...)
+			c.Data["LoginSources"] = newLoginSources
+			break
+		}
+	}
 	c.Success(LOGIN)
 }
 
@@ -173,6 +181,15 @@ func LoginPost(c *context.Context, f form.SignIn) {
 		default:
 			c.ServerError("UserLogin", err)
 		}
+		for i := range loginSources {
+			if loginSources[i].IsDefault {
+				c.Data["DefaultSource"] = *loginSources[i]
+				c.Data["login_source"] = loginSources[i].ID
+				newLoginSources := append(loginSources[:i], loginSources[i+1:]...)
+				c.Data["LoginSources"] = newLoginSources
+				break
+			}
+		}
 		return
 	}
 

+ 6 - 1
templates/admin/auth/edit.tmpl

@@ -186,7 +186,12 @@
 								<input name="is_active" type="checkbox" {{if .Source.IsActived}}checked{{end}}>
 							</div>
 						</div>
-
+						<div class="inline field">
+							<div class="ui checkbox">
+								<label><strong>{{.i18n.Tr "admin.auths.default_auth"}}</strong></label>
+								<input name="is_default" type="checkbox" {{if .Source.IsDefault}}checked{{end}}>
+							</div>
+						</div>
 						<div class="field">
 							<button class="ui green button">{{.i18n.Tr "admin.auths.update"}}</button>
 							{{if not .Source.LocalFile}}

+ 2 - 0
templates/admin/auth/list.tmpl

@@ -16,6 +16,7 @@
 								<th>{{.i18n.Tr "admin.auths.name"}}</th>
 								<th>{{.i18n.Tr "admin.auths.type"}}</th>
 								<th>{{.i18n.Tr "admin.auths.enabled"}}</th>
+								<th>{{.i18n.Tr "admin.auths.default"}}</th>
 								<th>{{.i18n.Tr "admin.auths.updated"}}</th>
 								<th>{{.i18n.Tr "admin.users.created"}}</th>
 								<th>{{.i18n.Tr "admin.users.edit"}}</th>
@@ -28,6 +29,7 @@
 									<td><a href="{{AppSubURL}}/admin/auths/{{.ID}}">{{.Name}}</a></td>
 									<td>{{.TypeName}}</td>
 									<td><i class="fa fa{{if .IsActived}}-check{{end}}-square-o"></i></td>
+									<td><i class="fa fa{{if .IsDefault}}-check{{end}}-square-o"></i></td>
 									<td><span class="poping up" data-content="{{DateFmtLong .Updated}}" data-variation="tiny">{{DateFmtShort .Updated}}</span></td>
 									<td>
 										{{if .Created.IsZero}}

+ 8 - 0
templates/admin/auth/new.tmpl

@@ -176,6 +176,7 @@
 								<input name="skip_verify" type="checkbox" {{if .skip_verify}}checked{{end}}>
 							</div>
 						</div>
+
 						<div class="inline field">
 							<div class="ui checkbox">
 								<label><strong>{{.i18n.Tr "admin.auths.activated"}}</strong></label>
@@ -183,6 +184,13 @@
 							</div>
 						</div>
 
+						<div class="inline field">
+							<div class="ui checkbox">
+								<label><strong>{{.i18n.Tr "admin.auths.default_auth"}}</strong></label>
+								<input name="is_default" type="checkbox" {{if .is_default}}checked{{end}}>
+							</div>
+						</div>
+
 						<div class="field">
 							<button class="ui green button">{{.i18n.Tr "admin.auths.new"}}</button>
 						</div>

+ 24 - 10
templates/user/auth/login.tmpl

@@ -22,16 +22,30 @@
 							<label for="password">{{.i18n.Tr "auth.auth_source"}}</label>
 							<div class="ui selection dropdown">
 								<input type="hidden" id="login_source" name="login_source" value="{{.login_source}}" required>
-								<span class="text">
-									{{.i18n.Tr "auth.local"}}
-								</span>
-								<i class="dropdown icon"></i>
-								<div class="menu">
-									<div class="item" data-value="0">{{.i18n.Tr "auth.local"}}</div>
-									{{range .LoginSources}}
-										<div class="item" data-value="{{.ID}}">{{.Name}}</div>
-									{{end}}
-								</div>
+								{{if .DefaultSource}}
+									<span class="text">
+										{{.DefaultSource.Name}}
+									</span>
+									<i class="dropdown icon"></i>
+									<div class="menu">
+										<div class="item" data-value="{{.DefaultSource.ID}}">{{.DefaultSource.Name}}</div>
+										<div class="item" data-value="0">{{.i18n.Tr "auth.local"}}</div>
+										{{range .LoginSources}}
+											<div class="item" data-value="{{.ID}}">{{.Name}}</div>
+										{{end}}
+									</div>
+								{{else}}
+									<span class="text">
+										{{.i18n.Tr "auth.local"}}
+									</span>
+									<i class="dropdown icon"></i>
+									<div class="menu">
+										<div class="item" data-value="0">{{.i18n.Tr "auth.local"}}</div>
+										{{range .LoginSources}}
+											<div class="item" data-value="{{.ID}}">{{.Name}}</div>
+										{{end}}
+									</div>
+								{{end}}
 							</div>
 						</div>
 					{{end}}