feat/role based access (#50)
* feat: add roles based access * feat: update roles env + todo * feat: add roles to update profile * feat: add role based oauth * feat: validate role for a given token
This commit is contained in:
@@ -1,29 +1,32 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/enum"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
type UserAuthInfo struct {
|
||||
Email string `json:"email"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
// type UserAuthInfo struct {
|
||||
// Email string `json:"email"`
|
||||
// ID string `json:"id"`
|
||||
// }
|
||||
|
||||
type JWTCustomClaim map[string]interface{}
|
||||
|
||||
type UserAuthClaim struct {
|
||||
*jwt.StandardClaims
|
||||
TokenType string `json:"token_type"`
|
||||
UserAuthInfo
|
||||
*JWTCustomClaim `json:"authorizer"`
|
||||
}
|
||||
|
||||
func CreateAuthToken(user UserAuthInfo, tokenType enum.TokenType) (string, int64, error) {
|
||||
func CreateAuthToken(user db.User, tokenType enum.TokenType, role string) (string, int64, error) {
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
|
||||
expiryBound := time.Hour
|
||||
if tokenType == enum.RefreshToken {
|
||||
@@ -33,12 +36,19 @@ func CreateAuthToken(user UserAuthInfo, tokenType enum.TokenType) (string, int64
|
||||
|
||||
expiresAt := time.Now().Add(expiryBound).Unix()
|
||||
|
||||
customClaims := JWTCustomClaim{
|
||||
"token_type": tokenType.String(),
|
||||
"email": user.Email,
|
||||
"id": user.ID,
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
constants.JWT_ROLE_CLAIM: role,
|
||||
}
|
||||
|
||||
t.Claims = &UserAuthClaim{
|
||||
&jwt.StandardClaims{
|
||||
ExpiresAt: expiresAt,
|
||||
},
|
||||
tokenType.String(),
|
||||
user,
|
||||
&customClaims,
|
||||
}
|
||||
|
||||
token, err := t.SignedString([]byte(constants.JWT_SECRET))
|
||||
@@ -63,14 +73,20 @@ func GetAuthToken(gc *gin.Context) (string, error) {
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func VerifyAuthToken(token string) (*UserAuthClaim, error) {
|
||||
func VerifyAuthToken(token string) (map[string]interface{}, error) {
|
||||
var res map[string]interface{}
|
||||
claims := &UserAuthClaim{}
|
||||
|
||||
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(constants.JWT_SECRET), nil
|
||||
})
|
||||
if err != nil {
|
||||
return claims, err
|
||||
return res, err
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
data, _ := json.Marshal(claims.JWTCustomClaim)
|
||||
json.Unmarshal(data, &res)
|
||||
res["exp"] = claims.ExpiresAt
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
20
server/utils/common.go
Normal file
20
server/utils/common.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func WriteToFile(filename string, data string) error {
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.WriteString(file, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return file.Sync()
|
||||
}
|
25
server/utils/initServer.go
Normal file
25
server/utils/initServer.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
)
|
||||
|
||||
// any jobs that we want to run at start of server can be executed here
|
||||
|
||||
// 1. create roles table and add the roles list from env to table
|
||||
|
||||
func InitServer() {
|
||||
roles := []db.Role{}
|
||||
for _, val := range constants.ROLES {
|
||||
roles = append(roles, db.Role{
|
||||
Role: val,
|
||||
})
|
||||
}
|
||||
err := db.Mgr.SaveRoles(roles)
|
||||
if err != nil {
|
||||
log.Println(`Error saving roles`, err)
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func IsSuperAdmin(gc *gin.Context) bool {
|
||||
secret := gc.Request.Header.Get("x-authorizer-admin-secret")
|
||||
if secret == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return secret == constants.ADMIN_SECRET
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func IsValidEmail(email string) bool {
|
||||
@@ -29,3 +30,52 @@ func IsValidRedirectURL(url string) bool {
|
||||
|
||||
return hasValidURL
|
||||
}
|
||||
|
||||
func IsSuperAdmin(gc *gin.Context) bool {
|
||||
secret := gc.Request.Header.Get("x-authorizer-admin-secret")
|
||||
if secret == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return secret == constants.ADMIN_SECRET
|
||||
}
|
||||
|
||||
func IsValidRolesArray(roles []string) bool {
|
||||
valid := true
|
||||
currentRoleMap := map[string]bool{}
|
||||
|
||||
for _, currentRole := range constants.ROLES {
|
||||
currentRoleMap[currentRole] = true
|
||||
}
|
||||
for _, inputRole := range roles {
|
||||
if !currentRoleMap[inputRole] {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
func IsValidRole(userRoles []string, role string) bool {
|
||||
valid := false
|
||||
for _, currentRole := range userRoles {
|
||||
if role == currentRole {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return valid
|
||||
}
|
||||
|
||||
func IsStringArrayEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
Reference in New Issue
Block a user