123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- package perm
- import (
- "errors"
- "fmt"
- "net/http"
- "reflect"
- "strings"
- "sync"
- "time"
- "github.com/iancoleman/strcase"
- "github.com/jinzhu/inflection"
- "github.com/ory/ladon"
- "github.com/ory/ladon/manager/memory"
- "github.com/sunfmin/reflectutils"
- "gorm.io/gorm"
- )
- const (
- Allowed = ladon.AllowAccess
- Denied = ladon.DenyAccess
- Anything = "*"
- Anybody = "*"
- Anonymous = "anonymous"
- )
- var PermissionDenied = errors.New("permission denied")
- type Context = ladon.Context
- type Conditions = ladon.Conditions
- type SubjectsFunc func(r *http.Request) []string
- type ContextFunc func(r *http.Request, objs []interface{}) Context
- type DBPolicy interface {
- LoadDBPolicies(db *gorm.DB, startFrom *time.Time) ([]*PolicyBuilder, []*PolicyBuilder)
- }
- type permRNer interface {
- PermissionRN() []string
- }
- func ToPermissionRN(v interface{}) []string {
- if pr, ok := v.(permRNer); ok {
- return pr.PermissionRN()
- }
- typeName := fmt.Sprint(reflect.TypeOf(v))
- ss := strings.Split(typeName, ".")
- typeName = ss[len(ss)-1]
- typeName = strings.NewReplacer("*", "", ".", "-").Replace(typeName)
- typeName = strcase.ToSnake(inflection.Plural(typeName))
- id, err := reflectutils.Get(v, "ID")
- if err == nil && len(fmt.Sprint(id)) > 0 && fmt.Sprint(id) != "0" {
- return []string{typeName, fmt.Sprint(id)}
- }
- return []string{typeName}
- }
- type Builder struct {
- m sync.Mutex
- policies []*PolicyBuilder
- ladon *ladon.Ladon
- subjectsFunc SubjectsFunc
- contextFunc ContextFunc
- dbPolicy *DBPolicyBuilder
- }
- func New() *Builder {
- return &Builder{
- ladon: &ladon.Ladon{
- Manager: memory.NewMemoryManager(),
- Matcher: &PathMatcher{},
- },
- }
- }
- func (b *Builder) Policies(ps ...*PolicyBuilder) (r *Builder) {
- b.DeletePolicies(b.policies...)
- b.policies = make([]*PolicyBuilder, 0)
- b.CreatePolicies(ps...)
- return b
- }
- func (b *Builder) createPolicy(p *PolicyBuilder) {
- p.setIDIfEmpty()
- err := b.ladon.Manager.Create(p.policy)
- if err != nil {
- panic(err)
- }
- b.policies = append(b.policies, p)
- }
- func (b *Builder) updatePolicy(p *PolicyBuilder) {
- i := b.findPolicyIndex(p.GetID())
- if i < 0 {
- return
- }
- err := b.ladon.Manager.Update(p.policy)
- if err != nil {
- panic(err)
- }
- b.policies[i] = p
- }
- func (b *Builder) findPolicyIndex(id string) int {
- for i, p := range b.policies {
- if p.GetID() == id {
- return i
- }
- }
- return -1
- }
- func (b *Builder) updateOrCreatePolicy(p *PolicyBuilder) {
- i := b.findPolicyIndex(p.GetID())
- if i < 0 {
- b.createPolicy(p)
- } else {
- b.updatePolicy(p)
- }
- }
- func (b *Builder) deletePolicy(p *PolicyBuilder) {
- for i, ep := range b.policies {
- if ep.GetID() == p.GetID() {
- err := b.ladon.Manager.Delete(p.GetID())
- if err != nil {
- panic(err)
- }
- b.policies = append(b.policies[:i], b.policies[i+1:]...)
- break
- }
- }
- }
- func (b *Builder) SubjectsFunc(v SubjectsFunc) (r *Builder) {
- b.subjectsFunc = v
- return b
- }
- func (b *Builder) GetSubjectsFunc() SubjectsFunc {
- return b.subjectsFunc
- }
- func (b *Builder) ContextFunc(v ContextFunc) (r *Builder) {
- b.contextFunc = v
- return b
- }
- func (b *Builder) GetContextFunc() ContextFunc {
- return b.contextFunc
- }
- func (b *Builder) DBPolicy(dpb *DBPolicyBuilder) (r *Builder) {
- b.dbPolicy = dpb
- go b.loopLoadDBPolicies(dpb.db, dpb.loadFrequency)
- return b
- }
- func (b *Builder) CreatePolicies(ps ...*PolicyBuilder) {
- b.m.Lock()
- defer b.m.Unlock()
- for _, p := range ps {
- b.createPolicy(p)
- }
- }
- func (b *Builder) UpdatePolicies(toUpdate ...*PolicyBuilder) {
- b.m.Lock()
- defer b.m.Unlock()
- for _, p := range toUpdate {
- b.updatePolicy(p)
- }
- }
- func (b *Builder) UpdateOrCreatePolicies(toUpdate ...*PolicyBuilder) {
- b.m.Lock()
- defer b.m.Unlock()
- for _, p := range toUpdate {
- b.updateOrCreatePolicy(p)
- }
- }
- func (b *Builder) DeletePolicies(toDelete ...*PolicyBuilder) {
- b.m.Lock()
- defer b.m.Unlock()
- for _, p := range toDelete {
- b.deletePolicy(p)
- }
- }
- func (b *Builder) LoadDBPoliciesToMemory(db *gorm.DB, startFrom *time.Time) {
- toUpdateOrCreate, toDelete := b.dbPolicy.model.LoadDBPolicies(db, startFrom)
- b.DeletePolicies(toDelete...)
- b.UpdateOrCreatePolicies(toUpdateOrCreate...)
- if Verbose {
- b.printPolices()
- }
- }
- func (b *Builder) loopLoadDBPolicies(db *gorm.DB, duration time.Duration) {
- now := time.Now()
- b.LoadDBPoliciesToMemory(db, nil)
- for next := range time.Tick(duration) {
- b.LoadDBPoliciesToMemory(db, &now)
- now = next
- }
- }
- func (b *Builder) printPolices() {
- allp, _ := b.ladon.Manager.GetAll(100, 0)
- fmt.Printf("all permission policies: \n")
- for _, p := range allp {
- fmt.Printf("%+v \n", p)
- }
- }
|