162 lines
3 KiB
Go
162 lines
3 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"github.com/google/uuid"
|
|
"github.com/open-policy-agent/opa/v1/rego"
|
|
)
|
|
|
|
type JWT struct {
|
|
SessionId string `json:"session_id"`
|
|
UserId int32 `json:"user_id"`
|
|
Role Role `json:"role"`
|
|
ExpiresAt int64 `json:"exp"`
|
|
IssuedAt int64 `json:"iat"`
|
|
NotBefore int64 `json:"nbf"`
|
|
Permissions []grant `json:"permissions"`
|
|
}
|
|
|
|
func (j JWT) Valid() error {
|
|
if uuid.Validate(j.SessionId) != nil {
|
|
return errors.New("invalid session id")
|
|
}
|
|
if j.UserId == 0 {
|
|
return errors.New("empty user id")
|
|
}
|
|
if j.ExpiresAt == 0 {
|
|
return errors.New("empty expires at")
|
|
}
|
|
if j.IssuedAt == 0 {
|
|
return errors.New("empty issued at")
|
|
}
|
|
if j.NotBefore == 0 {
|
|
return errors.New("empty not before")
|
|
}
|
|
if len(j.Permissions) == 0 {
|
|
return errors.New("empty permissions")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Role int32
|
|
|
|
const (
|
|
RoleGuest Role = -1
|
|
RoleStudent Role = 0
|
|
RoleTeacher Role = 1
|
|
RoleAdmin Role = 2
|
|
)
|
|
|
|
func (r Role) String() string {
|
|
switch r {
|
|
case RoleGuest:
|
|
return "guest"
|
|
case RoleStudent:
|
|
return "student"
|
|
case RoleTeacher:
|
|
return "teacher"
|
|
case RoleAdmin:
|
|
return "admin"
|
|
}
|
|
|
|
panic("invalid role")
|
|
}
|
|
|
|
type Action string
|
|
|
|
const (
|
|
Create Action = "create"
|
|
Read Action = "read"
|
|
Update Action = "update"
|
|
Delete Action = "delete"
|
|
)
|
|
|
|
type Resource string
|
|
|
|
const (
|
|
ResourceAnotherUser Resource = "another-user"
|
|
ResourceMeUser Resource = "me-user"
|
|
ResourceListUser Resource = "list-user"
|
|
|
|
ResourceOwnSession Resource = "own-session"
|
|
)
|
|
|
|
type grant struct {
|
|
Action Action `json:"action"`
|
|
Resource Resource `json:"resource"`
|
|
}
|
|
|
|
var Grants = map[string][]grant{
|
|
RoleGuest.String(): {},
|
|
RoleStudent.String(): {
|
|
{Read, ResourceAnotherUser},
|
|
{Read, ResourceMeUser},
|
|
{Update, ResourceOwnSession},
|
|
{Delete, ResourceOwnSession},
|
|
},
|
|
RoleTeacher.String(): {
|
|
{Create, ResourceAnotherUser},
|
|
{Read, ResourceAnotherUser},
|
|
{Read, ResourceMeUser},
|
|
{Read, ResourceListUser},
|
|
{Update, ResourceOwnSession},
|
|
{Delete, ResourceOwnSession},
|
|
},
|
|
RoleAdmin.String(): {
|
|
{Create, ResourceAnotherUser},
|
|
{Read, ResourceAnotherUser},
|
|
{Read, ResourceMeUser},
|
|
{Read, ResourceListUser},
|
|
{Update, ResourceAnotherUser},
|
|
{Update, ResourceOwnSession},
|
|
{Delete, ResourceAnotherUser},
|
|
{Delete, ResourceOwnSession},
|
|
},
|
|
}
|
|
|
|
const module = `package app.rbac
|
|
|
|
default allow := false
|
|
|
|
allow if {
|
|
some grant in input.role_grants[input.role]
|
|
|
|
input.action == grant.action
|
|
input.resource == grant.resource
|
|
}
|
|
`
|
|
|
|
var query rego.PreparedEvalQuery
|
|
|
|
func (r Role) HasPermission(action Action, resource Resource) bool {
|
|
ctx := context.TODO()
|
|
|
|
input := map[string]interface{}{
|
|
"action": action,
|
|
"resource": resource,
|
|
"role": r.String(),
|
|
"role_grants": Grants,
|
|
}
|
|
|
|
results, err := query.Eval(ctx, rego.EvalInput(input))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return results.Allowed()
|
|
}
|
|
|
|
func init() {
|
|
var err error
|
|
ctx := context.TODO()
|
|
|
|
query, err = rego.New(
|
|
rego.Query("data.app.rbac.allow"),
|
|
rego.Module("ms-auth.rego", module),
|
|
).PrepareForEval(ctx)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|