Initial Commit

This commit is contained in:
2021-02-11 15:47:42 -05:00
commit fec590b16e
249 changed files with 42571 additions and 0 deletions

57
internal/auth/auth.go Normal file
View File

@@ -0,0 +1,57 @@
package auth
import (
"errors"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
"reichard.io/imagini/graph/model"
"reichard.io/imagini/internal/config"
"reichard.io/imagini/internal/db"
)
type AuthManager struct {
DB *db.DBManager
Config *config.Config
}
func NewMgr(db *db.DBManager, c *config.Config) *AuthManager {
return &AuthManager{
DB: db,
Config: c,
}
}
func (auth *AuthManager) AuthenticateUser(user, password string) (model.User, bool) {
// Find User by Username / Email
foundUser := &model.User{Username: user}
_, err := auth.DB.User(foundUser)
// By Username
if errors.Is(err, gorm.ErrRecordNotFound) {
foundUser = &model.User{Email: user}
_, err = auth.DB.User(foundUser)
}
// By Email
if errors.Is(err, gorm.ErrRecordNotFound) {
log.Warn("[auth] User not found: ", user)
return *foundUser, false
} else if err != nil {
log.Error(err)
return *foundUser, false
}
log.Info("[auth] Authenticating user: ", foundUser.Username)
// Determine Type
switch foundUser.AuthType {
case "Local":
return *foundUser, authenticateLocalUser(*foundUser, password)
case "LDAP":
return *foundUser, authenticateLDAPUser(*foundUser, password)
default:
return *foundUser, false
}
}

126
internal/auth/jwt.go Normal file
View File

@@ -0,0 +1,126 @@
package auth
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/google/uuid"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwt"
log "github.com/sirupsen/logrus"
"reichard.io/imagini/graph/model"
)
func (auth *AuthManager) ValidateJWTRefreshToken(refreshJWT string) (jwt.Token, error) {
byteRefreshJWT := []byte(refreshJWT)
// Acquire Relevant Device
unverifiedToken, err := jwt.ParseBytes(byteRefreshJWT)
did, ok := unverifiedToken.Get("did")
if !ok {
return nil, errors.New("did does not exist")
}
deviceID, err := uuid.Parse(fmt.Sprintf("%v", did))
if err != nil {
return nil, errors.New("did does not parse")
}
device := &model.Device{ID: deviceID.String()}
_, err = auth.DB.Device(device)
if err != nil {
return nil, err
}
// Verify & Validate Token
verifiedToken, err := jwt.ParseBytes(byteRefreshJWT,
jwt.WithValidate(true),
jwt.WithVerify(jwa.HS256, []byte(*device.RefreshKey)),
)
if err != nil {
fmt.Println("failed to parse payload: ", err)
return nil, err
}
return verifiedToken, nil
}
func (auth *AuthManager) ValidateJWTAccessToken(accessJWT string) (jwt.Token, error) {
byteAccessJWT := []byte(accessJWT)
verifiedToken, err := jwt.ParseBytes(byteAccessJWT,
jwt.WithValidate(true),
jwt.WithVerify(jwa.HS256, []byte(auth.Config.JWTSecret)),
)
if err != nil {
return nil, err
}
return verifiedToken, nil
}
func (auth *AuthManager) CreateJWTRefreshToken(user model.User, device model.Device) (string, error) {
// Acquire Refresh Key
byteKey := []byte(*device.RefreshKey)
// Create New Token
tm := time.Now()
t := jwt.New()
t.Set(`did`, device.ID) // Device ID
t.Set(jwt.SubjectKey, user.ID) // User ID
t.Set(jwt.AudienceKey, `imagini`) // App ID
t.Set(jwt.IssuedAtKey, tm) // Issued At
// iOS & Android = Never Expiring Refresh Token
if device.Type != "iOS" && device.Type != "Android" {
t.Set(jwt.ExpirationKey, tm.Add(time.Hour*24)) // 1 Day Access Key
}
// Validate Token Creation
_, err := json.MarshalIndent(t, "", " ")
if err != nil {
fmt.Printf("failed to generate JSON: %s\n", err)
return "", err
}
// 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
}
func (auth *AuthManager) CreateJWTAccessToken(user model.User, device model.Device) (string, error) {
// Create New Token
tm := time.Now()
t := jwt.New()
t.Set(`did`, device.ID) // Device ID
t.Set(`role`, user.Role.String()) // User Role (Admin / User)
t.Set(jwt.SubjectKey, user.ID) // User ID
t.Set(jwt.AudienceKey, `imagini`) // App ID
t.Set(jwt.IssuedAtKey, tm) // Issued At
t.Set(jwt.ExpirationKey, tm.Add(time.Hour*2)) // 2 Hour 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
}

9
internal/auth/ldap.go Normal file
View File

@@ -0,0 +1,9 @@
package auth
import (
"reichard.io/imagini/graph/model"
)
func authenticateLDAPUser(user model.User, pw string) bool {
return false
}

18
internal/auth/local.go Normal file
View File

@@ -0,0 +1,18 @@
package auth
import (
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
"reichard.io/imagini/graph/model"
)
func authenticateLocalUser(user model.User, pw string) bool {
bPassword := []byte(pw)
err := bcrypt.CompareHashAndPassword([]byte(*user.Password), bPassword)
if err == nil {
log.Info("[auth] Authentication successfull: ", user.Username)
return true
}
log.Warn("[auth] Authentication failed: ", user.Username)
return false
}