mirror of
https://github.com/cuigh/swirl
synced 2024-12-29 07:12:11 +00:00
Add more LDAP options
This commit is contained in:
parent
902c2bca7c
commit
0ff76725bb
@ -1849,6 +1849,16 @@ var Swirl;
|
||||
let enabled = $(e.target).prop("checked");
|
||||
$("#fs-ldap").find("input:not(:checkbox)").prop("readonly", !enabled);
|
||||
});
|
||||
$("#ldap-auth-simple,#ldap-auth-bind").click(e => {
|
||||
if ($(e.target).val() == "0") {
|
||||
$("#div-auth-simple").show();
|
||||
$("#div-auth-bind").hide();
|
||||
}
|
||||
else {
|
||||
$("#div-auth-simple").hide();
|
||||
$("#div-auth-bind").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Setting.IndexPage = IndexPage;
|
||||
|
File diff suppressed because one or more lines are too long
@ -12,7 +12,7 @@ namespace Swirl.Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 Dispatcher 并绑定事件到页面元素上
|
||||
* Create a Dispatcher instance
|
||||
*
|
||||
* @param elem
|
||||
* @param event
|
||||
@ -23,11 +23,11 @@ namespace Swirl.Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册动作事件
|
||||
* Register event
|
||||
*
|
||||
* @param action
|
||||
* @param handler
|
||||
* @returns {Mtime.Util.Dispatcher}
|
||||
* @returns {Swirl.Core.Dispatcher}
|
||||
*/
|
||||
on(action: string, handler: (e: JQueryEventObject) => any): Dispatcher {
|
||||
this.events[action] = handler;
|
||||
@ -35,10 +35,10 @@ namespace Swirl.Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除动作事件
|
||||
* Unregister event
|
||||
*
|
||||
* @param action
|
||||
* @returns {Mtime.Util.Dispatcher}
|
||||
* @returns {Swirl.Core.Dispatcher}
|
||||
*/
|
||||
off(action: string): Dispatcher {
|
||||
delete this.events[action];
|
||||
@ -46,11 +46,11 @@ namespace Swirl.Core {
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定事件到页面元素上
|
||||
* Bind events to element
|
||||
*
|
||||
* @param elem
|
||||
* @param event
|
||||
* @returns {Mtime.Util.Dispatcher}
|
||||
* @returns {Swirl.Core.Dispatcher}
|
||||
*/
|
||||
bind(elem: string | JQuery | Element | Document, event: string = "click"): Dispatcher {
|
||||
$(elem).on(event, this.handle.bind(this));
|
||||
|
@ -77,7 +77,7 @@ namespace Swirl.Core {
|
||||
* Submit form by AJAX
|
||||
*
|
||||
* @param {string} url submit url
|
||||
* @returns {Mtime.Net.AjaxPostRequest}
|
||||
* @returns {Swirl.Core.AjaxPostRequest}
|
||||
*
|
||||
* @memberOf Form
|
||||
*/
|
||||
|
@ -5,6 +5,15 @@ namespace Swirl.Setting {
|
||||
let enabled = $(e.target).prop("checked");
|
||||
$("#fs-ldap").find("input:not(:checkbox)").prop("readonly", !enabled);
|
||||
});
|
||||
$("#ldap-auth-simple,#ldap-auth-bind").click(e => {
|
||||
if ($(e.target).val() == "0") {
|
||||
$("#div-auth-simple").show();
|
||||
$("#div-auth-bind").hide();
|
||||
} else {
|
||||
$("#div-auth-simple").hide();
|
||||
$("#div-auth-bind").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ var Setting = &settingBiz{}
|
||||
type settingBiz struct {
|
||||
}
|
||||
|
||||
// Get returns settings of swirl. If not found, default settings will be returned.
|
||||
func (b *settingBiz) Get() (setting *model.Setting, err error) {
|
||||
do(func(d dao.Interface) {
|
||||
setting, err = d.SettingGet()
|
||||
|
11
biz/user.go
11
biz/user.go
@ -193,6 +193,7 @@ func (b *userBiz) loginInternal(user *model.User, pwd string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: support tls and bind auth
|
||||
func (b *userBiz) loginLDAP(d dao.Interface, user *model.User, pwd string) error {
|
||||
setting, err := Setting.Get()
|
||||
if err != nil {
|
||||
@ -210,7 +211,9 @@ func (b *userBiz) loginLDAP(d dao.Interface, user *model.User, pwd string) error
|
||||
defer l.Close()
|
||||
|
||||
// bind
|
||||
err = l.Bind(user.LoginName, pwd)
|
||||
//err = l.Bind(user.LoginName, pwd)
|
||||
//err = l.Bind(setting.LDAP.BindDN, setting.LDAP.BindPassword) // bind auth
|
||||
err = l.Bind(fmt.Sprintf(setting.LDAP.UserDN, user.LoginName), pwd) // simple auth
|
||||
if err != nil {
|
||||
log.Get("user").Error("Login by LDAP failed: ", err)
|
||||
return ErrIncorrectAuth
|
||||
@ -224,7 +227,7 @@ func (b *userBiz) loginLDAP(d dao.Interface, user *model.User, pwd string) error
|
||||
// If user wasn't exist, we need create it
|
||||
req := ldap.NewSearchRequest(
|
||||
setting.LDAP.BaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=organizationalPerson)(userPrincipalName=%s))", user.LoginName),
|
||||
fmt.Sprintf(setting.LDAP.UserFilter, user.LoginName),
|
||||
[]string{setting.LDAP.NameAttr, setting.LDAP.EmailAttr},
|
||||
nil,
|
||||
)
|
||||
@ -232,8 +235,10 @@ func (b *userBiz) loginLDAP(d dao.Interface, user *model.User, pwd string) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(sr.Entries) == 0 {
|
||||
if length := len(sr.Entries); length == 0 {
|
||||
return ErrIncorrectAuth
|
||||
} else if length > 1 {
|
||||
return errors.New("Found more than one account when using LDAP authentication")
|
||||
}
|
||||
|
||||
entry := sr.Entries[0]
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cuigh/auxo/data"
|
||||
"github.com/cuigh/auxo/errors"
|
||||
"github.com/cuigh/auxo/net/web"
|
||||
"github.com/cuigh/auxo/util/cast"
|
||||
@ -12,7 +13,6 @@ import (
|
||||
"github.com/cuigh/swirl/biz/docker"
|
||||
"github.com/cuigh/swirl/misc"
|
||||
"github.com/cuigh/swirl/model"
|
||||
"mtime.com/auxo/data/set"
|
||||
)
|
||||
|
||||
// ServiceController is a controller of docker service
|
||||
@ -175,7 +175,11 @@ func serviceNew(ctx web.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
checkedNetworks := set.FromSlice(service.Networks, func(i int) interface{} { return service.Networks[i] })
|
||||
|
||||
checkedNetworks := data.NewSet()
|
||||
checkedNetworks.AddSlice(service.Networks, func(i int) interface{} {
|
||||
return service.Networks[i]
|
||||
})
|
||||
|
||||
m := newModel(ctx).Set("Service", service).Set("Registries", registries).
|
||||
Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
|
||||
@ -230,7 +234,8 @@ func serviceEdit(ctx web.Context) error {
|
||||
}
|
||||
|
||||
stack := service.Spec.Labels["com.docker.stack.namespace"]
|
||||
checkedNetworks := set.FromSlice(service.Endpoint.VirtualIPs, func(i int) interface{} { return service.Endpoint.VirtualIPs[i].NetworkID })
|
||||
checkedNetworks := data.NewSet()
|
||||
checkedNetworks.AddSlice(service.Endpoint.VirtualIPs, func(i int) interface{} { return service.Endpoint.VirtualIPs[i].NetworkID })
|
||||
|
||||
m := newModel(ctx).Set("Service", model.NewServiceInfo(service)).Set("Stack", stack).
|
||||
Set("Networks", networks).Set("CheckedNetworks", checkedNetworks).
|
||||
|
2
main.go
2
main.go
@ -29,7 +29,7 @@ func main() {
|
||||
misc.LoadOptions()
|
||||
app.Run(server())
|
||||
}
|
||||
app.Register(flag.All)
|
||||
app.Flags.Register(flag.All)
|
||||
app.Start()
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,22 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
// Setting represents the options of swirl.
|
||||
type Setting struct {
|
||||
LDAP struct {
|
||||
Enabled bool `bson:"enabled" json:"enabled,omitempty"`
|
||||
Address string `bson:"address" json:"address,omitempty"`
|
||||
BaseDN string `bson:"base_dn" json:"base_dn,omitempty"`
|
||||
NameAttr string `bson:"name_attr" json:"name_attr,omitempty"`
|
||||
EmailAttr string `bson:"email_attr" json:"email_attr,omitempty"`
|
||||
Enabled bool `bson:"enabled" json:"enabled,omitempty"`
|
||||
Address string `bson:"address" json:"address,omitempty"`
|
||||
Security int32 `bson:"security" json:"security,omitempty"` // 0-None/1-TLS/2-StartTLS
|
||||
TLSCert string `bson:"tls_cert" json:"tls_cert,omitempty"` // TLS cert
|
||||
TLSVerify bool `bson:"tls_verify" json:"tls_verify,omitempty"` // Verify cert
|
||||
Authentication int32 `bson:"auth" json:"auth,omitempty"` // 0-Bind/1-Simple
|
||||
BindDN string `bson:"bind_dn" json:"bind_dn,omitempty"` // DN to bind with
|
||||
BindPassword string `bson:"bind_pwd" json:"bind_pwd,omitempty"` // Bind DN password
|
||||
BaseDN string `bson:"base_dn" json:"base_dn,omitempty"` // Base search path for users
|
||||
UserDN string `bson:"user_dn" json:"user_dn,omitempty"` // Template for the DN of the user for simple auth
|
||||
UserFilter string `bson:"user_filter" json:"user_filter,omitempty"` // Search filter for user
|
||||
NameAttr string `bson:"name_attr" json:"name_attr,omitempty"`
|
||||
EmailAttr string `bson:"email_attr" json:"email_attr,omitempty"`
|
||||
} `bson:"ldap" json:"ldap,omitempty"`
|
||||
TimeZone struct {
|
||||
Name string `bson:"name" json:"name,omitempty"` // Asia/Shanghai
|
||||
|
@ -9,7 +9,7 @@
|
||||
{{ end }}
|
||||
|
||||
{{ block radio(id, name, value, label, checked, disabled=false) }}
|
||||
<input id="{{id ? id : (name + "-" + value)}}" name="{{name}}" value="{{value}}" type="radio" class="is-radio"{{if checked == value}} checked{{end}}{{if disabled}} disabled{{end}}{{yield content}}>
|
||||
<input id="{{id ? id : (name + "-" + value)}}" name="{{name}}" value="{{value}}" type="radio" class="is-radio"{{if eq(checked, value)}} checked{{end}}{{if disabled}} disabled{{end}}{{yield content}}>
|
||||
<label for="{{id ? id : (name + "-" + value)}}">{{label}}</label>
|
||||
{{ end }}
|
||||
|
||||
|
@ -65,6 +65,68 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Security</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
{{ yield radio(id="ldap.security-none", name="ldap.security", value="0", label="None", checked=.Setting.LDAP.Security) content}} data-type="integer"{{end}}
|
||||
{{ yield radio(id="ldap.security-tls", name="ldap.security", value="1", label="TLS", disabled=true) content}} data-type="integer"{{end}}
|
||||
{{ yield radio(id="ldap.security-starttls", name="ldap.security", value="2", label="StartTLS", disabled=true) content}} data-type="integer"{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Authentication</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
{{ yield radio(id="ldap-auth-simple", name="ldap.auth", value="0", label="Simple", checked=.Setting.LDAP.Authentication) content}} data-type="integer"{{end}}
|
||||
{{ yield radio(id="ldap-auth-bind", name="ldap.auth", value="1", label="Bind", checked=.Setting.LDAP.Authentication, disabled=true) content}} data-type="integer"{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div-auth-simple" class="field is-horizontal"{{ if .Setting.LDAP.Authentication == 1 }} style="display: none" {{ end }}>
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">User DN</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input name="ldap.user_dn" value="{{ .Setting.LDAP.UserDN }}" class="input" type="text" placeholder="e.g. cn=%s,dc=xxx,dc=com">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="div-auth-bind" class="field is-horizontal"{{ if .Setting.LDAP.Authentication == 0 }} style="display: none" {{ end }}>
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Bind</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">DN</a>
|
||||
</p>
|
||||
<div class="control is-expanded">
|
||||
<input name="ldap.bind_dn" value="{{ .Setting.LDAP.BindDN }}" class="input" type="text" placeholder="e.g. cn=search,dc=xxx,dc=com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">Password</a>
|
||||
</p>
|
||||
<div class="control is-expanded">
|
||||
<input name="ldap.bind_pwd" value="{{ .Setting.LDAP.BindPassword }}" class="input" type="password" autocomplete="new-password" placeholder="Bind DN password">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Base DN</label>
|
||||
@ -79,23 +141,35 @@
|
||||
</div>
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Username attribute</label>
|
||||
<label class="label">User filter</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input name="ldap.name_attr" value="{{ .Setting.LDAP.NameAttr }}" class="input" type="text" placeholder="e.g. displayName">
|
||||
<input name="ldap.user_filter" value="{{ .Setting.LDAP.UserFilter }}" class="input" type="text" placeholder="e.g. (&(objectClass=organizationalPerson)(sAMAccountName=%s))">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label is-normal">
|
||||
<label class="label">Email attribute</label>
|
||||
<label class="label">Attributes</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">Username</a>
|
||||
</p>
|
||||
<div class="control is-expanded">
|
||||
<input name="ldap.name_attr" value="{{ .Setting.LDAP.NameAttr }}" class="input" type="text" placeholder="e.g. displayName">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field has-addons">
|
||||
<p class="control">
|
||||
<a class="button is-static">Email</a>
|
||||
</p>
|
||||
<div class="control is-expanded">
|
||||
<input name="ldap.email_attr" value="{{ .Setting.LDAP.EmailAttr }}" class="input" type="text" placeholder="e.g. mail">
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user