Rework systemauth
This commit is contained in:
parent
368fe2bae6
commit
e53a49b47a
1
PKGBUILD
1
PKGBUILD
|
@ -31,4 +31,5 @@ package() {
|
||||||
cd "$pkgname-$pkgver"
|
cd "$pkgname-$pkgver"
|
||||||
install -Dm755 build/$pkgname "$pkgdir"/usr/bin/$pkgname
|
install -Dm755 build/$pkgname "$pkgdir"/usr/bin/$pkgname
|
||||||
install -Dm644 "$srcdir/$pkgname-$pkgver/resources/com.quexten.goldwarden.policy" "$pkgdir/usr/share/polkit-1/actions/com.quexten.goldwarden.policy"
|
install -Dm644 "$srcdir/$pkgname-$pkgver/resources/com.quexten.goldwarden.policy" "$pkgdir/usr/share/polkit-1/actions/com.quexten.goldwarden.policy"
|
||||||
|
chown root:root "$pkgdir/usr/share/polkit-1/actions/com.quexten.goldwarden.policy"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc"
|
"github.com/quexten/goldwarden/ipc"
|
||||||
)
|
)
|
||||||
|
@ -81,16 +80,16 @@ func ensureIsNotLocked(action Action) Action {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
systemauth.CreateSession(*ctx)
|
systemauth.CreatePinSession(*ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return action(request, cfg, vault, ctx)
|
return action(request, cfg, vault, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureBiometricsAuthorized(approvalType biometrics.Approval, action Action) Action {
|
func ensureBiometricsAuthorized(approvalType systemauth.SessionType, action Action) Action {
|
||||||
return func(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (ipc.IPCMessage, error) {
|
return func(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (ipc.IPCMessage, error) {
|
||||||
if !systemauth.CheckBiometrics(ctx, approvalType) {
|
if permission, err := systemauth.GetPermission(approvalType, *ctx, cfg); err != nil || !permission {
|
||||||
return ipc.IPCMessageFromPayload(ipc.ActionResponse{
|
return ipc.IPCMessageFromPayload(ipc.ActionResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
Message: "Polkit authorization failed required",
|
Message: "Polkit authorization failed required",
|
||||||
|
@ -101,6 +100,6 @@ func ensureBiometricsAuthorized(approvalType biometrics.Approval, action Action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureEverything(approvalType biometrics.Approval, action Action) Action {
|
func ensureEverything(approvalType systemauth.SessionType, action Action) Action {
|
||||||
return ensureIsNotLocked(ensureIsLoggedIn(ensureBiometricsAuthorized(approvalType, action)))
|
return ensureIsNotLocked(ensureIsLoggedIn(ensureBiometricsAuthorized(approvalType, action)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
|
@ -13,6 +14,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleGetBiometricsKey(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response ipc.IPCMessage, err error) {
|
func handleGetBiometricsKey(request ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, ctx *sockets.CallingContext) (response ipc.IPCMessage, err error) {
|
||||||
|
if !(systemauth.VerifyPinSession(*ctx) || biometrics.CheckBiometrics(biometrics.BrowserBiometrics)) {
|
||||||
|
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
|
||||||
|
Success: false,
|
||||||
|
Message: "not approved",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return ipc.IPCMessage{}, err
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access your vault encryption key for browser biometric unlock.", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
|
if approved, err := pinentry.GetApproval("Approve Credential Access", fmt.Sprintf("%s on %s>%s>%s is trying to access your vault encryption key for browser biometric unlock.", ctx.UserName, ctx.GrandParentProcessName, ctx.ParentProcessName, ctx.ProcessName)); err != nil || !approved {
|
||||||
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
|
response, err = ipc.IPCMessageFromPayload(ipc.ActionResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
@ -25,6 +37,9 @@ func handleGetBiometricsKey(request ipc.IPCMessage, cfg *config.Config, vault *v
|
||||||
}
|
}
|
||||||
|
|
||||||
masterKey, err := cfg.GetMasterKey()
|
masterKey, err := cfg.GetMasterKey()
|
||||||
|
if err != nil {
|
||||||
|
return ipc.IPCMessage{}, err
|
||||||
|
}
|
||||||
masterKeyB64 := base64.StdEncoding.EncodeToString(masterKey)
|
masterKeyB64 := base64.StdEncoding.EncodeToString(masterKey)
|
||||||
response, err = ipc.IPCMessageFromPayload(ipc.GetBiometricsKeyResponse{
|
response, err = ipc.IPCMessageFromPayload(ipc.GetBiometricsKeyResponse{
|
||||||
Key: masterKeyB64,
|
Key: masterKeyB64,
|
||||||
|
@ -33,5 +48,5 @@ func handleGetBiometricsKey(request ipc.IPCMessage, cfg *config.Config, vault *v
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetBiometricsKeyRequest, ensureEverything(biometrics.BrowserBiometrics, handleGetBiometricsKey))
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetBiometricsKeyRequest, ensureIsNotLocked(ensureIsLoggedIn(handleGetBiometricsKey)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc"
|
"github.com/quexten/goldwarden/ipc"
|
||||||
|
@ -45,5 +45,5 @@ func handleGetCliCredentials(request ipc.IPCMessage, cfg *config.Config, vault *
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetCLICredentialsRequest, ensureEverything(biometrics.AccessCredential, handleGetCliCredentials))
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetCLICredentialsRequest, ensureEverything(systemauth.AccessVault, handleGetCliCredentials))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc"
|
"github.com/quexten/goldwarden/ipc"
|
||||||
|
@ -157,6 +157,6 @@ func handleListLoginsRequest(request ipc.IPCMessage, cfg *config.Config, vault *
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageGetLoginRequest, ensureEverything(biometrics.AccessCredential, handleGetLoginCipher))
|
AgentActionsRegistry.Register(ipc.IPCMessageGetLoginRequest, ensureEverything(systemauth.AccessVault, handleGetLoginCipher))
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageListLoginsRequest, ensureEverything(biometrics.AccessCredential, handleListLoginsRequest))
|
AgentActionsRegistry.Register(ipc.IPCMessageListLoginsRequest, ensureEverything(systemauth.AccessVault, handleListLoginsRequest))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/ssh"
|
"github.com/quexten/goldwarden/agent/ssh"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc"
|
"github.com/quexten/goldwarden/ipc"
|
||||||
"github.com/quexten/goldwarden/logging"
|
"github.com/quexten/goldwarden/logging"
|
||||||
|
@ -57,6 +57,6 @@ func handleListSSH(msg ipc.IPCMessage, cfg *config.Config, vault *vault.Vault, c
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeCreateSSHKeyRequest, ensureEverything(biometrics.SSHKey, handleAddSSH))
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeCreateSSHKeyRequest, ensureEverything(systemauth.SSHKey, handleAddSSH))
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetSSHKeysRequest, ensureIsNotLocked(ensureIsLoggedIn(handleListSSH)))
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetSSHKeysRequest, ensureIsNotLocked(ensureIsLoggedIn(handleListSSH)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/ipc"
|
"github.com/quexten/goldwarden/ipc"
|
||||||
|
@ -181,6 +181,6 @@ func init() {
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeUnlockVaultRequest, handleUnlockVault)
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeUnlockVaultRequest, handleUnlockVault)
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeLockVaultRequest, handleLockVault)
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeLockVaultRequest, handleLockVault)
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeWipeVaultRequest, handleWipeVault)
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeWipeVaultRequest, handleWipeVault)
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeUpdateVaultPINRequest, ensureBiometricsAuthorized(biometrics.ChangePin, handleUpdateVaultPin))
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeUpdateVaultPINRequest, ensureBiometricsAuthorized(systemauth.AccessVault, handleUpdateVaultPin))
|
||||||
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetVaultPINStatusRequest, handlePinStatus)
|
AgentActionsRegistry.Register(ipc.IPCMessageTypeGetVaultPINStatusRequest, handlePinStatus)
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,11 +179,12 @@ func connectToWebsocket(ctx context.Context, vault *vault.Vault, cfg *config.Con
|
||||||
}
|
}
|
||||||
websocketLog.Info("AuthRequest details " + authRequest.RequestIpAddress + " " + authRequest.RequestDeviceType)
|
websocketLog.Info("AuthRequest details " + authRequest.RequestIpAddress + " " + authRequest.RequestDeviceType)
|
||||||
|
|
||||||
if approved, err := pinentry.GetApproval("Paswordless Login Request", "Do you want to allow "+authRequest.RequestIpAddress+" ("+authRequest.RequestDeviceType+") to login to your account?"); err != nil || !approved {
|
var message = "Do you want to allow " + authRequest.RequestIpAddress + " (" + authRequest.RequestDeviceType + ") to login to your account?"
|
||||||
|
if approved, err := pinentry.GetApproval("Paswordless Login Request", message); err != nil || !approved {
|
||||||
websocketLog.Info("AuthRequest denied")
|
websocketLog.Info("AuthRequest denied")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !biometrics.CheckBiometrics(biometrics.AccessCredential) {
|
if !biometrics.CheckBiometrics(biometrics.AccessVault) {
|
||||||
websocketLog.Info("AuthRequest denied - biometrics required")
|
websocketLog.Info("AuthRequest denied - biometrics required")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ type RuntimeConfig struct {
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
Pin string
|
Pin string
|
||||||
SessionToken string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigFile struct {
|
type ConfigFile struct {
|
||||||
|
@ -121,6 +120,18 @@ func (c *Config) Unlock(password string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) VerifyPin(password string) bool {
|
||||||
|
key := argon2.Key([]byte(password), []byte(c.ConfigFile.DeviceUUID), KDFIterations, KDFMemory, KDFThreads, 32)
|
||||||
|
debug.FreeOSMemory()
|
||||||
|
keyHash := sha3.Sum256(key)
|
||||||
|
configKeyHash := hex.EncodeToString(keyHash[:])
|
||||||
|
if cryptoSubtle.ConstantTimeCompare([]byte(configKeyHash), []byte(c.ConfigFile.ConfigKeyHash)) != 1 {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) Lock() {
|
func (c *Config) Lock() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth"
|
"github.com/quexten/goldwarden/agent/systemauth"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
"github.com/quexten/goldwarden/agent/vault"
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
"github.com/quexten/goldwarden/logging"
|
"github.com/quexten/goldwarden/logging"
|
||||||
|
@ -22,6 +22,7 @@ var log = logging.GetLogger("Goldwarden", "SSH")
|
||||||
|
|
||||||
type vaultAgent struct {
|
type vaultAgent struct {
|
||||||
vault *vault.Vault
|
vault *vault.Vault
|
||||||
|
config *config.Config
|
||||||
unlockRequestAction func() bool
|
unlockRequestAction func() bool
|
||||||
context sockets.CallingContext
|
context sockets.CallingContext
|
||||||
}
|
}
|
||||||
|
@ -77,7 +78,7 @@ func (vaultAgent vaultAgent) Sign(key ssh.PublicKey, data []byte) (*ssh.Signatur
|
||||||
return nil, errors.New("vault is locked")
|
return nil, errors.New("vault is locked")
|
||||||
}
|
}
|
||||||
|
|
||||||
systemauth.CreateSession(vaultAgent.context)
|
systemauth.CreatePinSession(vaultAgent.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
var signer ssh.Signer
|
var signer ssh.Signer
|
||||||
|
@ -103,7 +104,7 @@ func (vaultAgent vaultAgent) Sign(key ssh.PublicKey, data []byte) (*ssh.Signatur
|
||||||
return nil, errors.New("Approval not given")
|
return nil, errors.New("Approval not given")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !systemauth.CheckBiometrics(&vaultAgent.context, biometrics.SSHKey) {
|
if permission, err := systemauth.GetPermission(systemauth.SSHKey, vaultAgent.context, vaultAgent.config); err != nil || !permission {
|
||||||
log.Info("Sign Request for key: %s denied", key.Marshal())
|
log.Info("Sign Request for key: %s denied", key.Marshal())
|
||||||
return nil, errors.New("Biometrics not checked")
|
return nil, errors.New("Biometrics not checked")
|
||||||
}
|
}
|
||||||
|
@ -124,6 +125,7 @@ func (vaultAgent) Unlock(passphrase []byte) error {
|
||||||
|
|
||||||
type SSHAgentServer struct {
|
type SSHAgentServer struct {
|
||||||
vault *vault.Vault
|
vault *vault.Vault
|
||||||
|
config *config.Config
|
||||||
unlockRequestAction func() bool
|
unlockRequestAction func() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +133,10 @@ func (v *SSHAgentServer) SetUnlockRequestAction(action func() bool) {
|
||||||
v.unlockRequestAction = action
|
v.unlockRequestAction = action
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVaultAgent(vault *vault.Vault) SSHAgentServer {
|
func NewVaultAgent(vault *vault.Vault, config *config.Config) SSHAgentServer {
|
||||||
return SSHAgentServer{
|
return SSHAgentServer{
|
||||||
vault: vault,
|
vault: vault,
|
||||||
|
config: config,
|
||||||
unlockRequestAction: func() bool {
|
unlockRequestAction: func() bool {
|
||||||
log.Info("Unlock Request, but no action defined")
|
log.Info("Unlock Request, but no action defined")
|
||||||
return false
|
return false
|
||||||
|
@ -175,6 +178,7 @@ func (v SSHAgentServer) Serve() {
|
||||||
|
|
||||||
go agent.ServeAgent(vaultAgent{
|
go agent.ServeAgent(vaultAgent{
|
||||||
vault: v.vault,
|
vault: v.vault,
|
||||||
|
config: v.config,
|
||||||
unlockRequestAction: v.unlockRequestAction,
|
unlockRequestAction: v.unlockRequestAction,
|
||||||
context: callingContext,
|
context: callingContext,
|
||||||
}, conn)
|
}, conn)
|
||||||
|
|
|
@ -19,10 +19,8 @@ func init() {
|
||||||
type Approval string
|
type Approval string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AccessCredential Approval = "com.quexten.goldwarden.accesscredential"
|
AccessVault Approval = "com.quexten.goldwarden.accessvault"
|
||||||
ChangePin Approval = "com.quexten.goldwarden.changepin"
|
|
||||||
SSHKey Approval = "com.quexten.goldwarden.usesshkey"
|
SSHKey Approval = "com.quexten.goldwarden.usesshkey"
|
||||||
ModifyVault Approval = "com.quexten.goldwarden.modifyvault"
|
|
||||||
BrowserBiometrics Approval = "com.quexten.goldwarden.browserbiometrics"
|
BrowserBiometrics Approval = "com.quexten.goldwarden.browserbiometrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -12,18 +12,9 @@ const POLICY = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
||||||
|
|
||||||
<policyconfig>
|
<policyconfig>
|
||||||
<action id="com.quexten.goldwarden.accesscredential">
|
<action id="com.quexten.goldwarden.accessvault">
|
||||||
<description>Allow Credential Access</description>
|
<description>Allow access to the vault</description>
|
||||||
<message>Authenticate to allow access to a single credential</message>
|
<message>Allows access to the vault entries</message>
|
||||||
<defaults>
|
|
||||||
<allow_any>auth_self</allow_any>
|
|
||||||
<allow_inactive>auth_self</allow_inactive>
|
|
||||||
<allow_active>auth_self</allow_active>
|
|
||||||
</defaults>
|
|
||||||
</action>
|
|
||||||
<action id="com.quexten.goldwarden.changepin">
|
|
||||||
<description>Approve Pin Change</description>
|
|
||||||
<message>Authenticate to change your Goldwarden PIN.</message>
|
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_self</allow_any>
|
<allow_any>auth_self</allow_any>
|
||||||
<allow_inactive>auth_self</allow_inactive>
|
<allow_inactive>auth_self</allow_inactive>
|
||||||
|
@ -31,7 +22,7 @@ const POLICY = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
<action id="com.quexten.goldwarden.usesshkey">
|
<action id="com.quexten.goldwarden.usesshkey">
|
||||||
<description>Use Bitwarden SSH Key</description>
|
<description>Use SSH Key</description>
|
||||||
<message>Authenticate to use an SSH Key from your vault</message>
|
<message>Authenticate to use an SSH Key from your vault</message>
|
||||||
<defaults>
|
<defaults>
|
||||||
<allow_any>auth_self</allow_any>
|
<allow_any>auth_self</allow_any>
|
||||||
|
@ -39,15 +30,6 @@ const POLICY = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<allow_active>auth_self</allow_active>
|
<allow_active>auth_self</allow_active>
|
||||||
</defaults>
|
</defaults>
|
||||||
</action>
|
</action>
|
||||||
<action id="com.quexten.goldwarden.modifyvault">
|
|
||||||
<description>Modify Bitwarden Vault</description>
|
|
||||||
<message>Authenticate to allow modification of your Bitvarden vault in Goldwarden</message>
|
|
||||||
<defaults>
|
|
||||||
<allow_any>auth_self</allow_any>
|
|
||||||
<allow_inactive>auth_self</allow_inactive>
|
|
||||||
<allow_active>auth_self</allow_active>
|
|
||||||
</defaults>
|
|
||||||
</action>
|
|
||||||
<action id="com.quexten.goldwarden.browserbiometrics">
|
<action id="com.quexten.goldwarden.browserbiometrics">
|
||||||
<description>Browser Biometrics</description>
|
<description>Browser Biometrics</description>
|
||||||
<message>Authenticate to allow Goldwarden to unlock your browser.</message>
|
<message>Authenticate to allow Goldwarden to unlock your browser.</message>
|
||||||
|
@ -68,16 +50,18 @@ func CheckBiometrics(approvalType Approval) bool {
|
||||||
|
|
||||||
authority, err := polkit.NewAuthority()
|
authority, err := polkit.NewAuthority()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to create polkit authority: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := authority.CheckAuthorization(
|
result, err := authority.CheckAuthorization(
|
||||||
approvalType.String(),
|
approvalType.String(),
|
||||||
nil,
|
nil,
|
||||||
polkit.CheckAuthorizationAllowUserInteraction, "",
|
uint32(polkit.AuthenticationRequiredRetained), "",
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Error("Failed to create polkit authority: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,3 +69,32 @@ func CheckBiometrics(approvalType Approval) bool {
|
||||||
|
|
||||||
return result.IsAuthorized
|
return result.IsAuthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BiometricsWorking() bool {
|
||||||
|
if biometricsDisabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
authority, err := polkit.NewAuthority()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := authority.EnumerateActions("en")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
testFor := AccessVault
|
||||||
|
for _, action := range result {
|
||||||
|
if Approval(action.ActionID) == testFor {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,29 @@
|
||||||
package systemauth
|
package systemauth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/agent/sockets"
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
"github.com/quexten/goldwarden/agent/systemauth/biometrics"
|
||||||
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
"github.com/quexten/goldwarden/agent/systemauth/pinentry"
|
||||||
|
"github.com/quexten/goldwarden/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var log = logging.GetLogger("Goldwarden", "Systemauth")
|
||||||
|
|
||||||
const tokenExpiry = 10 * time.Minute
|
const tokenExpiry = 10 * time.Minute
|
||||||
|
|
||||||
|
type SessionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AccessVault SessionType = "com.quexten.goldwarden.accessvault"
|
||||||
|
SSHKey SessionType = "com.quexten.goldwarden.usesshkey"
|
||||||
|
Pin SessionType = "com.quexten.goldwarden.pin" // this counts as all other permissions
|
||||||
|
)
|
||||||
|
|
||||||
var sessionStore = SessionStore{
|
var sessionStore = SessionStore{
|
||||||
Store: []Session{},
|
Store: []Session{},
|
||||||
}
|
}
|
||||||
|
@ -19,26 +33,28 @@ type Session struct {
|
||||||
ParentPid int
|
ParentPid int
|
||||||
GrandParentPid int
|
GrandParentPid int
|
||||||
Expires time.Time
|
Expires time.Time
|
||||||
|
sessionType SessionType
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionStore struct {
|
type SessionStore struct {
|
||||||
Store []Session
|
Store []Session
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SessionStore) CreateSession(pid int, parentpid int, grandparentpid int) Session {
|
func (s *SessionStore) CreateSession(pid int, parentpid int, grandparentpid int, sessionType SessionType) Session {
|
||||||
var session = Session{
|
var session = Session{
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
ParentPid: parentpid,
|
ParentPid: parentpid,
|
||||||
GrandParentPid: grandparentpid,
|
GrandParentPid: grandparentpid,
|
||||||
Expires: time.Now().Add(tokenExpiry),
|
Expires: time.Now().Add(tokenExpiry),
|
||||||
|
sessionType: sessionType,
|
||||||
}
|
}
|
||||||
s.Store = append(s.Store, session)
|
s.Store = append(s.Store, session)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SessionStore) VerifySession(ctx sockets.CallingContext) bool {
|
func (s *SessionStore) verifySession(ctx sockets.CallingContext, sessionType SessionType) bool {
|
||||||
for _, session := range s.Store {
|
for _, session := range s.Store {
|
||||||
if session.ParentPid == ctx.ParentProcessPid && session.GrandParentPid == ctx.GrandParentProcessPid {
|
if session.ParentPid == ctx.ParentProcessPid && session.GrandParentPid == ctx.GrandParentProcessPid && (session.sessionType == sessionType || session.sessionType == Pin) {
|
||||||
if session.Expires.After(time.Now()) {
|
if session.Expires.After(time.Now()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -47,34 +63,70 @@ func (s *SessionStore) VerifySession(ctx sockets.CallingContext) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetApproval(title string, description string, requriesBiometrics bool) (bool, error) {
|
// with session
|
||||||
approval, err := pinentry.GetApproval(title, description)
|
func GetPermission(sessionType SessionType, ctx sockets.CallingContext, config *config.Config) (bool, error) {
|
||||||
if err != nil {
|
log.Info("Checking permission for " + ctx.ProcessName + " with session type " + string(sessionType))
|
||||||
return false, err
|
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
|
||||||
}
|
}
|
||||||
if requriesBiometrics {
|
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())))
|
||||||
biometricsApproval := biometrics.CheckBiometrics(biometrics.AccessCredential)
|
|
||||||
if !biometricsApproval {
|
if sessionStore.verifySession(ctx, sessionType) {
|
||||||
return false, nil
|
log.Info("Permission granted from cached session")
|
||||||
|
} else {
|
||||||
|
if biometrics.BiometricsWorking() {
|
||||||
|
biometricsApproval := biometrics.CheckBiometrics(biometricsApprovalType)
|
||||||
|
if !biometricsApproval {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
return approval, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no session
|
||||||
func CheckBiometrics(callingContext *sockets.CallingContext, approvalType biometrics.Approval) bool {
|
func CheckBiometrics(callingContext *sockets.CallingContext, approvalType biometrics.Approval) bool {
|
||||||
if sessionStore.VerifySession(*callingContext) {
|
var message = fmt.Sprintf("Do you want to grant %s>%s>%s one-time access your vault?", callingContext.GrandParentProcessName, callingContext.ParentProcessName, callingContext.ProcessName)
|
||||||
return true
|
var bioApproval = biometrics.CheckBiometrics(approvalType)
|
||||||
}
|
if !bioApproval {
|
||||||
|
|
||||||
var approval = biometrics.CheckBiometrics(approvalType)
|
|
||||||
if !approval {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionStore.CreateSession(callingContext.ProcessPid, callingContext.ParentProcessPid, callingContext.GrandParentProcessPid)
|
approval, err := pinentry.GetApproval("Goldwarden authorization", message)
|
||||||
return true
|
if err != nil {
|
||||||
|
log.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return approval
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSession(ctx sockets.CallingContext) {
|
func CreatePinSession(ctx sockets.CallingContext) {
|
||||||
sessionStore.CreateSession(ctx.ProcessPid, ctx.ParentProcessPid, ctx.GrandParentProcessPid)
|
sessionStore.CreateSession(ctx.ProcessPid, ctx.ParentProcessPid, ctx.GrandParentProcessPid, Pin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyPinSession(ctx sockets.CallingContext) bool {
|
||||||
|
return sessionStore.verifySession(ctx, Pin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ func StartUnixAgent(path string, runtimeConfig config.RuntimeConfig) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !runtimeConfig.DisableSSHAgent {
|
if !runtimeConfig.DisableSSHAgent {
|
||||||
vaultAgent := ssh.NewVaultAgent(vault)
|
vaultAgent := ssh.NewVaultAgent(vault, &cfg)
|
||||||
vaultAgent.SetUnlockRequestAction(func() bool {
|
vaultAgent.SetUnlockRequestAction(func() bool {
|
||||||
err := cfg.TryUnlock(vault)
|
err := cfg.TryUnlock(vault)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
6
main.go
6
main.go
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/quexten/goldwarden/agent/config"
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
"github.com/quexten/goldwarden/browserbiometrics"
|
"github.com/quexten/goldwarden/browserbiometrics"
|
||||||
"github.com/quexten/goldwarden/client/setup"
|
|
||||||
"github.com/quexten/goldwarden/cmd"
|
"github.com/quexten/goldwarden/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,7 +38,6 @@ func main() {
|
||||||
User: os.Getenv("GOLDWARDEN_AUTH_USER"),
|
User: os.Getenv("GOLDWARDEN_AUTH_USER"),
|
||||||
Password: os.Getenv("GOLDWARDEN_AUTH_PASSWORD"),
|
Password: os.Getenv("GOLDWARDEN_AUTH_PASSWORD"),
|
||||||
Pin: os.Getenv("GOLDWARDEN_PIN"),
|
Pin: os.Getenv("GOLDWARDEN_PIN"),
|
||||||
SessionToken: os.Getenv("GOLDWARDEN_SESSION_TOKEN"),
|
|
||||||
|
|
||||||
ConfigDirectory: configPath,
|
ConfigDirectory: configPath,
|
||||||
}
|
}
|
||||||
|
@ -57,9 +55,5 @@ func main() {
|
||||||
os.Setenv("GOLDWARDEN_SYSTEM_AUTH_DISABLED", "true")
|
os.Setenv("GOLDWARDEN_SYSTEM_AUTH_DISABLED", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setup.VerifySetup(runtimeConfig) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Execute(runtimeConfig)
|
cmd.Execute(runtimeConfig)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue