2023-08-21 13:52:06 +02:00
|
|
|
package twofactor
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/quexten/goldwarden/agent/config"
|
|
|
|
"github.com/quexten/goldwarden/agent/systemauth"
|
2023-08-21 18:37:34 +02:00
|
|
|
"github.com/quexten/goldwarden/logging"
|
2023-08-21 13:52:06 +02:00
|
|
|
)
|
|
|
|
|
2023-08-21 18:37:34 +02:00
|
|
|
var twofactorLog = logging.GetLogger("Goldwarden", "TwoFactor")
|
2023-08-21 13:52:06 +02:00
|
|
|
|
|
|
|
func PerformSecondFactor(resp *TwoFactorResponse, cfg *config.Config) (TwoFactorProvider, []byte, error) {
|
2023-09-11 14:14:41 +02:00
|
|
|
if provider, isInMap := resp.TwoFactorProviders2[WebAuthn]; isInMap {
|
2023-08-21 13:52:06 +02:00
|
|
|
if isFido2Enabled {
|
2023-09-11 14:14:41 +02:00
|
|
|
chall := provider["challenge"].(string)
|
2023-08-21 13:52:06 +02:00
|
|
|
|
|
|
|
var creds []string
|
2023-09-11 14:14:41 +02:00
|
|
|
for _, credential := range provider["allowCredentials"].([]interface{}) {
|
2023-08-21 13:52:06 +02:00
|
|
|
publicKey := credential.(map[string]interface{})["id"].(string)
|
|
|
|
creds = append(creds, publicKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := Fido2TwoFactor(chall, creds, cfg)
|
|
|
|
if err != nil {
|
|
|
|
return WebAuthn, nil, err
|
|
|
|
}
|
|
|
|
return WebAuthn, []byte(result), err
|
|
|
|
} else {
|
|
|
|
twofactorLog.Warn("WebAuthn is enabled for the account but goldwarden is not compiled with FIDO2 support")
|
|
|
|
}
|
|
|
|
}
|
2023-09-11 14:14:41 +02:00
|
|
|
if _, isInMap := resp.TwoFactorProviders2[Authenticator]; isInMap {
|
2023-08-21 13:52:06 +02:00
|
|
|
token, err := systemauth.GetPassword("Authenticator Second Factor", "Enter your two-factor auth code")
|
|
|
|
return Authenticator, []byte(token), err
|
|
|
|
}
|
2023-09-11 14:14:41 +02:00
|
|
|
if _, isInMap := resp.TwoFactorProviders2[Email]; isInMap {
|
2023-08-21 13:52:06 +02:00
|
|
|
token, err := systemauth.GetPassword("Email Second Factor", "Enter your two-factor auth code")
|
|
|
|
return Email, []byte(token), err
|
|
|
|
}
|
|
|
|
|
|
|
|
return Authenticator, []byte{}, errors.New("no second factor available")
|
|
|
|
}
|
|
|
|
|
|
|
|
type TwoFactorProvider int
|
|
|
|
|
|
|
|
const (
|
|
|
|
Authenticator TwoFactorProvider = 0
|
|
|
|
Email TwoFactorProvider = 1
|
|
|
|
Duo TwoFactorProvider = 2 //Not supported
|
|
|
|
YubiKey TwoFactorProvider = 3 //Not supported
|
|
|
|
U2f TwoFactorProvider = 4 //Not supported
|
|
|
|
Remember TwoFactorProvider = 5 //Not supported
|
|
|
|
OrganizationDuo TwoFactorProvider = 6 //Not supported
|
|
|
|
WebAuthn TwoFactorProvider = 7
|
|
|
|
_TwoFactorProviderMax = 8 //Not supported
|
|
|
|
)
|
|
|
|
|
|
|
|
func (t *TwoFactorProvider) UnmarshalText(text []byte) error {
|
|
|
|
i, err := strconv.Atoi(string(text))
|
|
|
|
if err != nil || i < 0 || i >= _TwoFactorProviderMax {
|
|
|
|
return fmt.Errorf("invalid two-factor auth provider: %q", text)
|
|
|
|
}
|
|
|
|
*t = TwoFactorProvider(i)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type TwoFactorResponse struct {
|
|
|
|
TwoFactorProviders2 map[TwoFactorProvider]map[string]interface{}
|
|
|
|
}
|