Skip to content

Commit

Permalink
Dont fail inmmediately if no devices and other mfa configured (#205)
Browse files Browse the repository at this point in the history
* Also adding debug messages

* aslo pass via golint

* missed rename
  • Loading branch information
cviecco authored Oct 30, 2023
1 parent 5f3ee7c commit f8542f4
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ endif
BINARY=keymaster

# These are the values we want to pass for Version and BuildTime
VERSION=1.14.0
VERSION=1.14.1
#BUILD_TIME=`date +%FT%T%z`

# Setup the -ldflags option for go build here, interpolate the variable values
Expand Down
2 changes: 1 addition & 1 deletion keymaster.spec
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Name: keymaster
Version: 1.14.0
Version: 1.14.1
Release: 1%{?dist}
Summary: Short term access certificate generator and client

Expand Down
131 changes: 76 additions & 55 deletions lib/client/twofa/twofa.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func createKeyBodyRequest(method, urlStr, filedata string) (*http.Request, error
}

func doCertRequest(signer crypto.Signer, client *http.Client, userName string,
baseUrl,
baseURL,
certType string,
addGroups bool,
userAgentString string, logger log.DebugLogger) ([]byte, error) {
Expand Down Expand Up @@ -97,15 +97,15 @@ func doCertRequest(signer crypto.Signer, client *http.Client, userName string,
urlPostfix = "&addGroups=true"
logger.Debugln(0, "adding \"addGroups\" to request")
}
requestURL := baseUrl + "/certgen/" + userName + "?type=" + certType + urlPostfix
requestURL := baseURL + "/certgen/" + userName + "?type=" + certType + urlPostfix
return doCertRequestInternal(client, requestURL, serializedPubkey, userAgentString, logger)
}

func doCertRequestInternal(client *http.Client,
url, filedata string,
targetURL, filedata string,
userAgentString string, logger log.Logger) ([]byte, error) {

req, err := createKeyBodyRequest("POST", url, filedata)
req, err := createKeyBodyRequest("POST", targetURL, filedata)
if err != nil {
return nil, err
}
Expand All @@ -118,28 +118,85 @@ func doCertRequestInternal(client *http.Client,

defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("got error from call %s, url='%s'\n", resp.Status, url)
return nil, fmt.Errorf("got error from call %s, url='%s'", resp.Status, targetURL)
}
return ioutil.ReadAll(resp.Body)
}

// tryFidoMFA performs a fido authentication step
// If there are no devices connected it will return false, nil
// if there are fido devices connected it will return
// true, nil on successul MFA and false, error on failure to
// perform the Fido authentication
func tryFidoMFA(
baseURL string,
client *http.Client,
userAgentString string,
logger log.DebugLogger,
) (bool, error) {
// Linux support for the new library is not quite correct
// so for now we keep using the old library (pure u2f)
// for linux cli as default. Windows 10 and MacOS have been
// tested successfully.
// The env variable allows us to swap what library is used by
// default
useWebAuthh := true
if runtime.GOOS == "linux" {
useWebAuthh = false
}
if os.Getenv("KEYMASTER_USEALTU2FLIB") != "" {
useWebAuthh = !useWebAuthh
}
var err error
if !useWebAuthh {
devices, err := u2fhid.Devices()
if err != nil {
logger.Printf("could not open hid devices err=%s", err)
return false, err
}
if len(devices) < 1 {
logger.Debugf(2, "No Fido devices found")
return false, nil
}
err = u2f.DoU2FAuthenticate(
client, baseURL, userAgentString, logger)
if err != nil {

return false, err
}
return true, nil
}
devices := u2fhost.Devices()
if devices == nil || len(devices) < 1 {
logger.Debugf(2, "No Fido devices found")
return false, nil
}
err = u2f.WithDevicesDoWebAuthnAuthenticate(devices,
client, baseURL, userAgentString, logger)
if err != nil {
logger.Printf("Error doing hid webathentication err=%s", err)
return false, err
}
return true, nil
}

// This assumes the http client has a non-nul cookie jar
func authenticateUser(
userName string,
password []byte,
baseUrl string,
baseURL string,
skip2fa bool,
client *http.Client,
userAgentString string,
logger log.DebugLogger) (err error) {
if client == nil {
return fmt.Errorf("http client is nil")
}
loginUrl := baseUrl + proto.LoginPath
loginURL := baseURL + proto.LoginPath
form := url.Values{}
form.Add("username", userName)
form.Add("password", string(password[:]))
req, err := http.NewRequest("POST", loginUrl,
req, err := http.NewRequest("POST", loginURL,
strings.NewReader(form.Encode()))
if err != nil {
return err
Expand Down Expand Up @@ -227,52 +284,16 @@ func authenticateUser(
// upgrade to u2f
successful2fa := false

// Linux support for the new library is not quite correct
// so for now we keep using the old library (pure u2f)
// for linux cli as default. Windows 10 and MacOS have been
// tested successfully.
// The env variable allows us to swap what library is used by
// default
useWebAuthh := true
if runtime.GOOS == "linux" {
useWebAuthh = false
}
if os.Getenv("KEYMASTER_USEALTU2FLIB") != "" {
useWebAuthh = !useWebAuthh
}
if !skip2fa {
if allowU2F {
if useWebAuthh {
err = u2f.WithDevicesDoWebAuthnAuthenticate(u2fhost.Devices(),
client, baseUrl, userAgentString, logger)
if err != nil {
logger.Printf("Error doing hid webathentication err=%s", err)
return err
}
successful2fa = true

} else {
devices, err := u2fhid.Devices()
if err != nil {
logger.Printf("could not open hid devices err=%s", err)
return err
}
if len(devices) > 0 {

err = u2f.DoU2FAuthenticate(
client, baseUrl, userAgentString, logger)
if err != nil {

return err
}
successful2fa = true
}
successful2fa, err = tryFidoMFA(baseURL, client, userAgentString, logger)
if err != nil {
return err
}
}

if allowTOTP && !successful2fa {
err = totp.DoTOTPAuthenticate(
client, baseUrl, userAgentString, logger)
client, baseURL, userAgentString, logger)
if err != nil {

return err
Expand All @@ -281,7 +302,7 @@ func authenticateUser(
}
if allowVIP && !successful2fa {
err = pushtoken.DoVIPAuthenticate(
client, baseUrl, userAgentString, logger)
client, baseURL, userAgentString, logger)
if err != nil {

return err
Expand All @@ -291,7 +312,7 @@ func authenticateUser(
// TODO: do better logic when both VIP and OKTA are configured
if allowOkta2FA && !successful2fa {
err = pushtoken.DoOktaAuthenticate(
client, baseUrl, userAgentString, logger)
client, baseURL, userAgentString, logger)
if err != nil {
return err
}
Expand All @@ -315,22 +336,22 @@ func authenticateToTargetUrls(
skip2fa bool,
client *http.Client,
userAgentString string,
logger log.DebugLogger) (baseUrl string, err error) {
logger log.DebugLogger) (baseURL string, err error) {

for _, baseUrl = range targetUrls {
logger.Printf("attempting to target '%s' for '%s'\n", baseUrl, userName)
for _, baseURL = range targetUrls {
logger.Printf("attempting to target '%s' for '%s'\n", baseURL, userName)
err = authenticateUser(
userName,
password,
baseUrl,
baseURL,
skip2fa,
client,
userAgentString,
logger)
if err != nil {
continue
}
return baseUrl, nil
return baseURL, nil

}
return "", fmt.Errorf("Failed to Authenticate to any URL")
Expand Down

0 comments on commit f8542f4

Please sign in to comment.