Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dont fail inmmediately if no devices and other mfa configured #205

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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