2024-08-14 15:36:43 +05:00
|
|
|
package models
|
|
|
|
|
|
|
|
import (
|
2025-02-25 18:33:15 +05:00
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/open-policy-agent/opa/v1/rego"
|
2024-08-14 15:36:43 +05:00
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2024-12-30 20:04:26 +05:00
|
|
|
type Role int32
|
2024-08-14 15:36:43 +05:00
|
|
|
|
2024-12-30 20:04:26 +05:00
|
|
|
const (
|
2025-02-25 18:33:15 +05:00
|
|
|
RoleGuest Role = -1
|
|
|
|
RoleStudent Role = 0
|
|
|
|
RoleTeacher Role = 1
|
|
|
|
RoleAdmin Role = 2
|
2024-12-30 20:04:26 +05:00
|
|
|
)
|
2024-08-14 15:36:43 +05:00
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
func (r Role) String() string {
|
|
|
|
switch r {
|
|
|
|
case RoleGuest:
|
|
|
|
return "guest"
|
|
|
|
case RoleStudent:
|
|
|
|
return "student"
|
|
|
|
case RoleTeacher:
|
|
|
|
return "teacher"
|
|
|
|
case RoleAdmin:
|
|
|
|
return "admin"
|
|
|
|
}
|
2024-08-14 15:36:43 +05:00
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
panic("invalid role")
|
2024-12-30 20:04:26 +05:00
|
|
|
}
|
2024-08-14 15:36:43 +05:00
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
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"`
|
2024-08-14 15:36:43 +05:00
|
|
|
}
|
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
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},
|
|
|
|
},
|
2024-08-14 15:36:43 +05:00
|
|
|
}
|
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
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
|
2024-08-14 15:36:43 +05:00
|
|
|
}
|
2025-02-25 18:33:15 +05:00
|
|
|
`
|
2024-08-14 15:36:43 +05:00
|
|
|
|
2024-12-30 20:04:26 +05:00
|
|
|
type User struct {
|
|
|
|
Id int32 `db:"id"`
|
|
|
|
Username string `db:"username"`
|
|
|
|
HashedPassword string `db:"hashed_pwd"`
|
|
|
|
CreatedAt time.Time `db:"created_at"`
|
|
|
|
ModifiedAt time.Time `db:"modified_at"`
|
|
|
|
Role Role `db:"role"`
|
2024-08-14 15:36:43 +05:00
|
|
|
}
|
|
|
|
|
2025-02-25 18:33:15 +05:00
|
|
|
func (user *User) MarshalJSON() ([]byte, error) {
|
|
|
|
m := map[string]interface{}{
|
|
|
|
"id": user.Id,
|
|
|
|
"username": user.Username,
|
|
|
|
"created_at": user.CreatedAt,
|
|
|
|
"modified_at": user.ModifiedAt,
|
|
|
|
"role": user.Role,
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(m)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) IsSamePwd(password string) bool {
|
2024-12-30 20:04:26 +05:00
|
|
|
err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), []byte(password))
|
2024-08-14 15:36:43 +05:00
|
|
|
if err != nil {
|
2025-02-25 18:33:15 +05:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2024-08-14 15:36:43 +05:00
|
|
|
}
|
|
|
|
}
|