Add RBAC support with roles, permissions, and session management. Implement middleware for authentication and CSRF protection. Enhance audit logging with additional fields. Update HTTP handlers and routes for new features.

This commit is contained in:
2025-12-13 17:44:09 +00:00
parent d69e01bbaf
commit 8100f87686
44 changed files with 3262 additions and 76 deletions

89
internal/auth/password.go Normal file
View File

@@ -0,0 +1,89 @@
package auth
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"fmt"
"strings"
"golang.org/x/crypto/argon2"
)
const (
// Argon2id parameters
argon2Memory = 64 * 1024 // 64 MB
argon2Iterations = 3
argon2Parallelism = 2
argon2SaltLength = 16
argon2KeyLength = 32
)
// HashPassword hashes a password using Argon2id
func HashPassword(password string) (string, error) {
// Generate a random salt
salt := make([]byte, argon2SaltLength)
if _, err := rand.Read(salt); err != nil {
return "", err
}
// Hash the password
hash := argon2.IDKey([]byte(password), salt, argon2Iterations, argon2Memory, argon2Parallelism, argon2KeyLength)
// Encode the hash and salt
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
// Return the encoded hash in the format: $argon2id$v=19$m=65536,t=3,p=2$salt$hash
return fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
argon2.Version, argon2Memory, argon2Iterations, argon2Parallelism, b64Salt, b64Hash), nil
}
// VerifyPassword verifies a password against a hash
func VerifyPassword(password, encodedHash string) (bool, error) {
// Parse the encoded hash
parts := strings.Split(encodedHash, "$")
if len(parts) != 6 {
return false, errors.New("invalid hash format")
}
if parts[1] != "argon2id" {
return false, errors.New("unsupported hash algorithm")
}
// Parse version
var version int
if _, err := fmt.Sscanf(parts[2], "v=%d", &version); err != nil {
return false, err
}
if version != argon2.Version {
return false, errors.New("incompatible version")
}
// Parse parameters
var memory, iterations, parallelism int
if _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &memory, &iterations, &parallelism); err != nil {
return false, err
}
// Decode salt and hash
salt, err := base64.RawStdEncoding.DecodeString(parts[4])
if err != nil {
return false, err
}
hash, err := base64.RawStdEncoding.DecodeString(parts[5])
if err != nil {
return false, err
}
// Compute the hash of the password
otherHash := argon2.IDKey([]byte(password), salt, uint32(iterations), uint32(memory), uint8(parallelism), uint32(len(hash)))
// Compare hashes in constant time
if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
return true, nil
}
return false, nil
}