(WIP) Refresh & Access
This commit is contained in:
@@ -1,20 +1,37 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
"reichard.io/imagini/internal/db"
|
||||
"reichard.io/imagini/internal/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"reichard.io/imagini/internal/db"
|
||||
"reichard.io/imagini/internal/config"
|
||||
"reichard.io/imagini/internal/models"
|
||||
"reichard.io/imagini/internal/session"
|
||||
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lestrrat-go/jwx/jwa"
|
||||
"github.com/lestrrat-go/jwx/jwt"
|
||||
)
|
||||
|
||||
type AuthManager struct {
|
||||
DB *db.DBManager
|
||||
DB *db.DBManager
|
||||
Config *config.Config
|
||||
Session *session.SessionManager
|
||||
}
|
||||
|
||||
func NewMgr(db *db.DBManager) *AuthManager {
|
||||
func NewMgr(db *db.DBManager, c *config.Config) *AuthManager {
|
||||
session := session.NewMgr()
|
||||
return &AuthManager{
|
||||
DB: db,
|
||||
Config: c,
|
||||
Session: session,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,3 +63,123 @@ func (auth *AuthManager) AuthenticateUser(creds models.APICredentials) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (auth *AuthManager) ValidateJWTToken(userJWT string) bool {
|
||||
byteUserJWT := []byte(userJWT)
|
||||
|
||||
serverToken, err := jwt.ParseBytes(byteUserJWT, jwt.WithVerify(jwa.HS256, auth.Config.JWTSecret))
|
||||
if err != nil {
|
||||
fmt.Println("failed to parse payload: ", err)
|
||||
}
|
||||
|
||||
uid, ok := serverToken.Get("uid");
|
||||
if !ok {
|
||||
fmt.Println("failed to acquire uid")
|
||||
}
|
||||
|
||||
userID := fmt.Sprintf("%v", uid)
|
||||
userKey := auth.Session.Get(userID)
|
||||
|
||||
userToken, err := jwt.ParseBytes(byteUserJWT, jwt.WithVerify(jwa.HS256, userKey))
|
||||
if err != nil {
|
||||
fmt.Println("failed to parse payload: ", err)
|
||||
}
|
||||
_ = userToken
|
||||
|
||||
// TODO:
|
||||
// - Get User ID from UNVALIDATED token
|
||||
// - Lookup user key, concat with server key
|
||||
// - Validate with concatted user & server key
|
||||
// validatedToken, err := jwt.ParseBytes(byteUserJWT, jwt.WithVerify(jwa.HS256, concatKey))
|
||||
// if err != nil {
|
||||
// fmt.Printf("failed to parse payload: %s\n", err)
|
||||
// }
|
||||
|
||||
// userToken := auth.Session.Get(userID)
|
||||
// log.Info("[auth] DEBUG: ", userToken)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (auth *AuthManager) RevokeRefreshToken() {
|
||||
|
||||
}
|
||||
|
||||
func (auth *AuthManager) ValidateRefreshToken(refreshToken, deviceID string) bool {
|
||||
// Acquire Device
|
||||
deviceUUID, err := uuid.Parse(deviceID)
|
||||
device := models.Device{Base: models.Base{UUID: deviceUUID}}
|
||||
foundDevice, err := auth.DB.Device(device)
|
||||
|
||||
// Validate Expiration
|
||||
expTime, err := time.Parse(time.RFC3339, foundDevice.RefreshExp)
|
||||
if expTime.Before(time.Now()) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate Token
|
||||
bRefreshToken :=[]byte(refreshToken)
|
||||
err = bcrypt.CompareHashAndPassword([]byte(foundDevice.RefreshToken), bRefreshToken)
|
||||
if err == nil {
|
||||
log.Info("[auth] Refresh Token validation succeeded: ", foundDevice.UUID)
|
||||
return true
|
||||
}
|
||||
log.Warn("[auth] Refresh Token validation failed: ", foundDevice.UUID)
|
||||
return false
|
||||
}
|
||||
|
||||
func (auth *AuthManager) UpdateRefreshToken(deviceID string) error {
|
||||
// TODO:
|
||||
// - Remove Refresh token from Session AND DB
|
||||
// - Call CreateRefreshToken
|
||||
return nil
|
||||
}
|
||||
|
||||
func (auth *AuthManager) CreateRefreshToken(deviceID string) (string, error) {
|
||||
// TODO:
|
||||
// - Create regular bcrypt password
|
||||
// - Create Expiration (Depends on Device Type)
|
||||
// - Store in DB: DeviceID, ValidUntil
|
||||
|
||||
generatedToken := uuid.New().String()
|
||||
hashedRefreshToken, err := bcrypt.GenerateFromPassword([]byte(generatedToken), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return "", err
|
||||
}
|
||||
_ = string(hashedRefreshToken)
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (auth *AuthManager) CreateJWTAccessToken(user, role, deviceID string) (string, error) {
|
||||
// Create New Token
|
||||
tm := time.Now()
|
||||
t := jwt.New()
|
||||
t.Set(`did`, deviceID) // Device ID
|
||||
t.Set(`role`, role) // User Role (Admin / User)
|
||||
t.Set(jwt.SubjectKey, user) // User ID
|
||||
t.Set(jwt.AudienceKey, `imagini`) // App ID
|
||||
t.Set(jwt.IssuedAtKey, tm) // Issued At
|
||||
t.Set(jwt.ExpirationKey, tm.Add(time.Minute * 30)) // 30 Minute Access Key
|
||||
|
||||
// Validate Token Creation
|
||||
_, err := json.MarshalIndent(t, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("failed to generate JSON: %s\n", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Use Server Key
|
||||
byteKey := []byte(auth.Config.JWTSecret)
|
||||
|
||||
// Sign Token
|
||||
signed, err := jwt.Sign(t, jwa.HS256, byteKey)
|
||||
if err != nil {
|
||||
log.Printf("failed to sign token: %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Return Token
|
||||
return string(signed), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user