goldwarden-vaultwarden-bitw.../cli/agent/systemauth/systemauth.go

153 lines
4.6 KiB
Go

package systemauth
import (
"fmt"
"math"
"time"
"github.com/quexten/goldwarden/cli/agent/config"
"github.com/quexten/goldwarden/cli/agent/sockets"
"github.com/quexten/goldwarden/cli/agent/systemauth/biometrics"
"github.com/quexten/goldwarden/cli/agent/systemauth/pinentry"
"github.com/quexten/goldwarden/cli/logging"
)
var log = logging.GetLogger("Goldwarden", "Systemauth")
const tokenExpiry = 60 * time.Minute
const SSHTTL = 60 * time.Minute
type SessionType string
const (
AccessVault SessionType = "com.quexten.goldwarden.accessvault"
SSHKey SessionType = "com.quexten.goldwarden.usesshkey"
Pin SessionType = "com.quexten.goldwarden.pin"
)
var sessionStore = SessionStore{
Store: []Session{},
}
type Session struct {
Pid int
ParentPid int
GrandParentPid int
Expires time.Time
sessionType SessionType
}
type SessionStore struct {
Store []Session
}
func (s *SessionStore) CreateSession(pid int, parentpid int, grandparentpid int, sessionType SessionType, ttl time.Duration) Session {
var session = Session{
Pid: pid,
ParentPid: parentpid,
GrandParentPid: grandparentpid,
Expires: time.Now().Add(ttl),
sessionType: sessionType,
}
s.Store = append(s.Store, session)
return session
}
func (s *SessionStore) verifySession(ctx sockets.CallingContext, sessionType SessionType) bool {
for _, session := range s.Store {
if session.ParentPid == ctx.ParentProcessPid && session.GrandParentPid == ctx.GrandParentProcessPid && session.sessionType == sessionType {
if session.Expires.After(time.Now()) {
return true
}
}
}
return false
}
// with session
func GetPermission(sessionType SessionType, ctx sockets.CallingContext, config *config.Config) (bool, error) {
if ctx.Authenticated {
return true, nil
}
log.Info("Checking permission for " + ctx.ProcessName + " with session type " + string(sessionType))
var actionDescription = ""
biometricsApprovalType := biometrics.AccessVault
switch sessionType {
case AccessVault:
actionDescription = "access the vault"
biometricsApprovalType = biometrics.AccessVault
case SSHKey:
actionDescription = "use an SSH key for signing"
biometricsApprovalType = biometrics.SSHKey
}
var message = fmt.Sprintf("Do you want to authorize %s>%s>%s to %s? (This choice will be remembered for %d minutes)", ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName, actionDescription, int(math.Floor(tokenExpiry.Minutes())))
if sessionStore.verifySession(ctx, sessionType) {
log.Info("Permission granted from cached session")
} else {
if !sessionStore.verifySession(ctx, Pin) {
if biometrics.BiometricsWorking() {
biometricsApproval := biometrics.CheckBiometrics(biometricsApprovalType)
if !biometricsApproval {
return false, nil
}
} else {
log.Warn("Biometrics is not available, asking for pin")
pin, err := pinentry.GetPassword("Enter PIN", "Biometrics is not available. Enter your pin to authorize this action. "+message)
if err != nil {
return false, err
}
if !config.VerifyPin(pin) {
return false, nil
}
}
}
// approval, err := pinentry.GetApproval("Goldwarden authorization", message)
// if err != nil || !approval {
// return false, err
// }
log.Info("Permission granted, creating session")
sessionStore.CreateSession(ctx.ProcessPid, ctx.ParentProcessPid, ctx.GrandParentProcessPid, sessionType, tokenExpiry)
}
return true, nil
}
// no session
func CheckBiometrics(callingContext *sockets.CallingContext, approvalType biometrics.Approval) bool {
var message = fmt.Sprintf("Do you want to grant %s>%s>%s one-time access your vault?", callingContext.GrandParentProcessName, callingContext.ParentProcessName, callingContext.ProcessName)
var bioApproval = biometrics.CheckBiometrics(approvalType)
if !bioApproval {
return false
}
approval, err := pinentry.GetApproval("Goldwarden authorization", message)
if err != nil {
log.Error(err.Error())
}
return approval
}
func CreatePinSession(ctx sockets.CallingContext, ttl time.Duration) Session {
return sessionStore.CreateSession(ctx.ProcessPid, ctx.ParentProcessPid, ctx.GrandParentProcessPid, Pin, ttl)
}
func VerifyPinSession(ctx sockets.CallingContext) bool {
return sessionStore.verifySession(ctx, Pin)
}
func CreateSSHSession(ctx sockets.CallingContext) Session {
return sessionStore.CreateSession(ctx.ProcessPid, ctx.ParentProcessPid, ctx.GrandParentProcessPid, SSHKey, SSHTTL)
}
func GetSSHSession(ctx sockets.CallingContext) bool {
return sessionStore.verifySession(ctx, SSHKey)
}
func WipeSessions() {
sessionStore.Store = []Session{}
}