mirror of
https://github.com/cuigh/swirl
synced 2025-06-26 18:16:50 +00:00
Refactor authentication & authorization modules
This commit is contained in:
132
security/auth.go
Normal file
132
security/auth.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cuigh/auxo/cache"
|
||||
"github.com/cuigh/auxo/log"
|
||||
"github.com/cuigh/auxo/net/web"
|
||||
"github.com/cuigh/auxo/security"
|
||||
"github.com/cuigh/auxo/security/certify"
|
||||
"github.com/cuigh/auxo/security/certify/ldap"
|
||||
"github.com/cuigh/auxo/security/passwd"
|
||||
"github.com/cuigh/swirl/biz"
|
||||
"github.com/cuigh/swirl/model"
|
||||
)
|
||||
|
||||
const pkgName = "swirl.security"
|
||||
|
||||
// Validator is the authenticator function of swirl.
|
||||
func Validator(setting *model.Setting) func(name, pwd string) (ticket string, err error) {
|
||||
ldapRealm := createLDAPRealm(setting)
|
||||
return func(name, pwd string) (ticket string, err error) {
|
||||
var (
|
||||
su security.User
|
||||
mu *model.User
|
||||
)
|
||||
|
||||
// try find user first
|
||||
mu, err = biz.User.GetByName(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if mu != nil && mu.Type == model.UserTypeInternal { // internal user
|
||||
if !passwd.Validate(pwd, mu.Password, mu.Salt) {
|
||||
err = certify.ErrInvalidToken
|
||||
}
|
||||
} else if ldapRealm != nil { // user not exist or ldap user
|
||||
su, err = ldapRealm.Login(certify.NewSimpleToken(name, pwd))
|
||||
if err == nil && mu == nil { // create user if not exists
|
||||
lu := su.(*ldap.User)
|
||||
mu = &model.User{
|
||||
Type: model.UserTypeLDAP,
|
||||
LoginName: lu.LoginName(),
|
||||
Name: lu.Name(),
|
||||
Email: lu.Email(),
|
||||
}
|
||||
err = biz.User.Create(mu, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// replace user session, one session is allowed per user.
|
||||
if err == nil {
|
||||
ticket, err = biz.User.UpdateSession(mu.ID)
|
||||
}
|
||||
|
||||
// create event
|
||||
if err == nil {
|
||||
biz.Event.CreateAuthentication(model.EventActionLogin, mu.ID, mu.LoginName, mu.Name)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func createLDAPRealm(setting *model.Setting) certify.Realm {
|
||||
if setting.LDAP.Enabled {
|
||||
opts := []ldap.Option{
|
||||
ldap.NameAttr(setting.LDAP.NameAttr),
|
||||
ldap.EmailAttr(setting.LDAP.EmailAttr),
|
||||
ldap.UserFilter(setting.LDAP.UserFilter),
|
||||
ldap.Security(ldap.SecurityPolicy(setting.LDAP.Security)),
|
||||
}
|
||||
if setting.LDAP.Authentication == 1 {
|
||||
opts = append(opts, ldap.Binding(setting.LDAP.BindDN, setting.LDAP.BindPassword))
|
||||
}
|
||||
return ldap.New(setting.LDAP.Address, setting.LDAP.BaseDN, setting.LDAP.UserDN, opts...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Identifier is used to identity user.
|
||||
func Identifier(token string) (user web.User) {
|
||||
const cacheKey = "auth_user"
|
||||
|
||||
session, err := biz.User.GetSession(token)
|
||||
if err != nil {
|
||||
log.Get(pkgName).Errorf("Load session failed: %v", err)
|
||||
return
|
||||
}
|
||||
if session == nil || session.Expires.Before(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
// try find from cache first
|
||||
value := cache.Get(cacheKey, session.UserID)
|
||||
if !value.IsNil() {
|
||||
user = &model.AuthUser{}
|
||||
if err = value.Scan(user); err == nil {
|
||||
return
|
||||
}
|
||||
log.Get(pkgName).Warnf("Load auth user from cache failed: %v", err)
|
||||
}
|
||||
|
||||
u, err := biz.User.GetByID(session.UserID)
|
||||
if err != nil {
|
||||
log.Get(pkgName).Errorf("Load user failed: %v", err)
|
||||
return
|
||||
}
|
||||
if u == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var roles []*model.Role
|
||||
if roles, err = getRoles(u); err == nil {
|
||||
user = model.NewAuthUser(u, roles)
|
||||
cache.Set(user, cacheKey, session.UserID)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getRoles(u *model.User) (roles []*model.Role, err error) {
|
||||
if len(u.Roles) > 0 {
|
||||
roles = make([]*model.Role, len(u.Roles))
|
||||
for i, id := range u.Roles {
|
||||
roles[i], err = biz.Role.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
223
security/perm.go
Normal file
223
security/perm.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cuigh/auxo/net/web"
|
||||
"github.com/cuigh/swirl/biz"
|
||||
"github.com/cuigh/swirl/model"
|
||||
)
|
||||
|
||||
// Checker check permission of user
|
||||
func Checker(user web.User, h web.HandlerInfo) bool {
|
||||
if au, ok := user.(*model.AuthUser); ok {
|
||||
return au.IsAllowed(h.Name())
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Permiter is a middleware for validate data permission.
|
||||
func Permiter(next web.HandlerFunc) web.HandlerFunc {
|
||||
return func(ctx web.Context) error {
|
||||
opt := ctx.Handler().Option("perm")
|
||||
if opt != "" {
|
||||
array := strings.Split(opt, ",")
|
||||
err := biz.Perm.Check(ctx.User(), array[0], array[1], ctx.P(array[2]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Perm holds permission key and description.
|
||||
type Perm struct {
|
||||
Key string
|
||||
Text string
|
||||
}
|
||||
|
||||
// PermGroup holds information of a perm group.
|
||||
type PermGroup struct {
|
||||
Name string
|
||||
Perms []Perm
|
||||
}
|
||||
|
||||
// Perms holds all valid perm groups.
|
||||
var Perms = []PermGroup{
|
||||
{
|
||||
Name: "Registry",
|
||||
Perms: []Perm{
|
||||
{Key: "registry.list", Text: "View list"},
|
||||
{Key: "registry.create", Text: "Create"},
|
||||
{Key: "registry.delete", Text: "Delete"},
|
||||
{Key: "registry.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Node",
|
||||
Perms: []Perm{
|
||||
{Key: "node.list", Text: "View list"},
|
||||
{Key: "node.detail", Text: "View detail"},
|
||||
{Key: "node.raw", Text: "View raw"},
|
||||
{Key: "node.edit", Text: "View edit"},
|
||||
{Key: "node.update", Text: "Update"},
|
||||
{Key: "node.delete", Text: "Delete"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Network",
|
||||
Perms: []Perm{
|
||||
{Key: "network.list", Text: "View list"},
|
||||
{Key: "network.new", Text: "View new"},
|
||||
{Key: "network.detail", Text: "View detail"},
|
||||
{Key: "network.raw", Text: "View raw"},
|
||||
{Key: "network.create", Text: "Create"},
|
||||
{Key: "network.delete", Text: "Delete"},
|
||||
{Key: "network.disconnect", Text: "Disconnect container"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Service",
|
||||
Perms: []Perm{
|
||||
{Key: "service.list", Text: "View list"},
|
||||
{Key: "service.new", Text: "View new"},
|
||||
{Key: "service.detail", Text: "View detail"},
|
||||
{Key: "service.raw", Text: "View raw"},
|
||||
{Key: "service.logs", Text: "View logs"},
|
||||
{Key: "service.edit", Text: "View edit"},
|
||||
{Key: "service.create", Text: "Create"},
|
||||
{Key: "service.delete", Text: "Delete"},
|
||||
{Key: "service.update", Text: "Update"},
|
||||
{Key: "service.scale", Text: "Scale"},
|
||||
{Key: "service.rollback", Text: "Rollback"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Template",
|
||||
Perms: []Perm{
|
||||
{Key: "template.list", Text: "View list"},
|
||||
{Key: "template.new", Text: "View new"},
|
||||
{Key: "template.edit", Text: "View edit"},
|
||||
{Key: "template.create", Text: "Create"},
|
||||
{Key: "template.delete", Text: "Delete"},
|
||||
{Key: "template.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Stack",
|
||||
Perms: []Perm{
|
||||
{Key: "stack.task.list", Text: "View task list"},
|
||||
{Key: "stack.task.delete", Text: "Delete task"},
|
||||
{Key: "stack.archive.list", Text: "View archive list"},
|
||||
{Key: "stack.archive.new", Text: "View archive new"},
|
||||
{Key: "stack.archive.detail", Text: "View archive detail"},
|
||||
{Key: "stack.archive.edit", Text: "View archive edit"},
|
||||
{Key: "stack.archive.delete", Text: "Delete archive"},
|
||||
{Key: "stack.archive.create", Text: "Create archive"},
|
||||
{Key: "stack.archive.update", Text: "Update archive"},
|
||||
{Key: "stack.archive.deploy", Text: "Deploy archive"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Task",
|
||||
Perms: []Perm{
|
||||
{Key: "task.list", Text: "View list"},
|
||||
{Key: "task.detail", Text: "View detail"},
|
||||
{Key: "task.raw", Text: "View raw"},
|
||||
{Key: "task.logs", Text: "View logs"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Image",
|
||||
Perms: []Perm{
|
||||
{Key: "image.list", Text: "View list"},
|
||||
{Key: "image.detail", Text: "View detail"},
|
||||
{Key: "image.raw", Text: "View raw"},
|
||||
{Key: "image.delete", Text: "Delete"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Container",
|
||||
Perms: []Perm{
|
||||
{Key: "container.list", Text: "View list"},
|
||||
{Key: "container.detail", Text: "View detail"},
|
||||
{Key: "container.raw", Text: "View raw"},
|
||||
{Key: "container.logs", Text: "View logs"},
|
||||
{Key: "container.delete", Text: "Delete"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Volume",
|
||||
Perms: []Perm{
|
||||
{Key: "volume.list", Text: "View list"},
|
||||
{Key: "volume.new", Text: "View new"},
|
||||
{Key: "volume.detail", Text: "View detail"},
|
||||
{Key: "volume.raw", Text: "View raw"},
|
||||
{Key: "volume.create", Text: "Create"},
|
||||
{Key: "volume.delete", Text: "Delete"},
|
||||
{Key: "volume.prune", Text: "Prune"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Secret",
|
||||
Perms: []Perm{
|
||||
{Key: "secret.list", Text: "View list"},
|
||||
{Key: "secret.new", Text: "View new"},
|
||||
{Key: "secret.edit", Text: "View edit"},
|
||||
{Key: "secret.create", Text: "Create"},
|
||||
{Key: "secret.delete", Text: "Delete"},
|
||||
{Key: "secret.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Config",
|
||||
Perms: []Perm{
|
||||
{Key: "config.list", Text: "View list"},
|
||||
{Key: "config.new", Text: "View new"},
|
||||
{Key: "config.edit", Text: "View edit"},
|
||||
{Key: "config.create", Text: "Create"},
|
||||
{Key: "config.delete", Text: "Delete"},
|
||||
{Key: "config.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Role",
|
||||
Perms: []Perm{
|
||||
{Key: "role.list", Text: "View list"},
|
||||
{Key: "role.new", Text: "View new"},
|
||||
{Key: "role.detail", Text: "View detail"},
|
||||
{Key: "role.edit", Text: "View edit"},
|
||||
{Key: "role.create", Text: "Create"},
|
||||
{Key: "role.delete", Text: "Delete"},
|
||||
{Key: "role.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "User",
|
||||
Perms: []Perm{
|
||||
{Key: "user.list", Text: "View list"},
|
||||
{Key: "user.new", Text: "View new"},
|
||||
{Key: "user.detail", Text: "View detail"},
|
||||
{Key: "user.edit", Text: "View edit"},
|
||||
{Key: "user.create", Text: "Create"},
|
||||
{Key: "user.delete", Text: "Delete"},
|
||||
{Key: "user.update", Text: "Update"},
|
||||
{Key: "user.block", Text: "Block"},
|
||||
{Key: "user.unblock", Text: "Unblock"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Setting",
|
||||
Perms: []Perm{
|
||||
{Key: "setting.edit", Text: "View edit"},
|
||||
{Key: "setting.update", Text: "Update"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Event",
|
||||
Perms: []Perm{
|
||||
{Key: "event.list", Text: "View list"},
|
||||
},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user