Skip to content

Commit

Permalink
webauthn tests p1 (#230)
Browse files Browse the repository at this point in the history
* first test round inital part of webauthn registration. Needed as part of webauthn migration to new lib

* addressing comments
  • Loading branch information
cviecco authored Jun 12, 2024
1 parent a2caeee commit a40a44c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 8 deletions.
17 changes: 10 additions & 7 deletions cmd/keymasterd/2fa_webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const webAutnRegististerRequestPath = "/webauthn/RegisterRequest/"

// RegisterRequest?
func (state *RuntimeState) webauthnBeginRegistration(w http.ResponseWriter, r *http.Request) {
logger.Debugf(3, "top of webauthnBeginRegistration")
state.logger.Debugf(3, "top of webauthnBeginRegistration")
if state.sendFailureToClientIfLocked(w, r) {
return
}
Expand All @@ -47,16 +47,18 @@ func (state *RuntimeState) webauthnBeginRegistration(w http.ResponseWriter, r *h
if len(pieces) >= 4 {
assumedUser = pieces[3]
} else {
logger.Debugf(1, "webauthnBeginRegistration: bad number of pieces")
state.logger.Debugf(1, "webauthnBeginRegistration: bad number of pieces")
http.Error(w, "error", http.StatusBadRequest)
return
}
state.logger.Debugf(3, "top of webauthnBeginRegistration: after piece processing ")
// TODO(camilo_viecco1): reorder checks so that simple checks are done before checking user creds
authData, err := state.checkAuth(w, r, state.getRequiredWebUIAuthLevel())
if err != nil {
logger.Debugf(1, "%v", err)
state.logger.Debugf(1, "webauthnBeginRegistration: checkAuth Failed %v", err)
return
}
state.logger.Debugf(3, "top of webauthnBeginRegistration: after authentication ")
w.(*instrumentedwriter.LoggingWriter).SetUsername(authData.Username)

// Check that they can change other users
Expand All @@ -68,20 +70,21 @@ func (state *RuntimeState) webauthnBeginRegistration(w http.ResponseWriter, r *h

profile, _, fromCache, err := state.LoadUserProfile(assumedUser)
if err != nil {
logger.Printf("webauthnBeginRegistration: loading profile error: %v", err)
state.logger.Printf("webauthnBeginRegistration: loading profile error: %v", err)
http.Error(w, "error", http.StatusInternalServerError)
return

}
if fromCache {
logger.Printf("DB is being cached and requesting registration aborting it")
state.logger.Printf("DB is being cached and requesting registration aborting it")
http.Error(w, "db backend is offline for writes", http.StatusServiceUnavailable)
return
}
state.logger.Debugf(3, "top of webauthnBeginRegistration: after profile loadingn ")

profile.FixupCredential(assumedUser, assumedUser)
logger.Debugf(2, "webauthnBeginRegistration profile=%+v", profile)
logger.Debugf(2, "webauthnBeginRegistration: About to begin BeginRegistration")
state.logger.Debugf(2, "webauthnBeginRegistration profile=%+v", profile)
state.logger.Debugf(2, "webauthnBeginRegistration: About to begin BeginRegistration")
options, sessionData, err := state.webAuthn.BeginRegistration(profile)
if err != nil {
state.logger.Printf("webauthnBeginRegistration: begin login failed %s", err)
Expand Down
97 changes: 97 additions & 0 deletions cmd/keymasterd/2fa_webauthn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package main

import (
"bytes"
"io"
"net/http"
"os"
"testing"

"github.com/Cloud-Foundations/keymaster/lib/webapi/v0/proto"

"github.com/duo-labs/webauthn/webauthn"
)

func TestWebAuthnRegistrationBegin(t *testing.T) {

state, passwdFile, err := setupValidRuntimeStateSigner(t)
if err != nil {
t.Fatal(err)
}
defer os.Remove(passwdFile.Name()) // clean up

state.Config.Base.AllowedAuthBackendsForWebUI = append(state.Config.Base.AllowedAuthBackendsForWebUI, proto.AuthTypeU2F)

state.signerPublicKeyToKeymasterKeys()

// cviecco -> probablt dont need tempdir
dir, err := os.MkdirTemp("", "example")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir) // clean up
state.Config.Base.DataDirectory = dir
err = initDB(state)
if err != nil {
t.Fatal(err)
}
state.HostIdentity = "testHost"
// end of copy
logger = state.logger

u2fAppID = "https://" + state.HostIdentity // this should include the port...but not needed for this test as we assume 443
state.webAuthn, err = webauthn.New(&webauthn.Config{
RPDisplayName: "Keymaster Server", // Display Name for your site
RPID: state.HostIdentity, // Generally the domain name for your site
RPOrigin: u2fAppID, // The origin URL for WebAuthn requests
// RPIcon: "https://duo.com/logo.png", // Optional icon URL for your site
})
if err != nil {
t.Fatal(err)
}

// end of setup

req, err := http.NewRequest("GET", webAutnRegististerRequestPath+"username", nil)
if err != nil {
t.Fatal(err)
//return nil, err
}
cookieVal, err := state.setNewAuthCookie(nil, "username", AuthTypeU2F)
if err != nil {
t.Fatal(err)
}
authCookie := http.Cookie{Name: authCookieName, Value: cookieVal}
req.AddCookie(&authCookie)

regData, err := checkRequestHandlerCode(req, state.webauthnBeginRegistration, http.StatusOK)
if err != nil {
t.Fatal(err)
}
/*
resultAccessToken := newTOTPPageTemplateData{}
*/
body := regData.Result().Body
var b bytes.Buffer
_, err = io.Copy(&b, body)
if err != nil {
t.Fatal(err)
}
t.Logf("regdata=%s\n", b.String())

/*
err = json.NewDecoder(body).Decode(&resultAccessToken)
if err != nil {
t.Fatal(err)
}
t.Logf("totpDataToken='%+v'", resultAccessToken)
*/

/*
Example post for finalization:
{
"{\"id\":\"_N2M7t9Qe2rwS4asNZ15I4Thd-nkXow6_lyDT6CURM3gD1sAq0FyMnf8NDOARMWMjjNgPfeHpPWP0Q8nkx-v7pNRuR0IwRHkvZeZxaV3Ql3HFigByVOhuB3OCq2em8Ve\",\"rawId\":\"_N2M7t9Qe2rwS4asNZ15I4Thd-nkXow6_lyDT6CURM3gD1sAq0FyMnf8NDOARMWMjjNgPfeHpPWP0Q8nkx-v7pNRuR0IwRHkvZeZxaV3Ql3HFigByVOhuB3OCq2em8Ve\",\"type\":\"public-key\",\"response\":{\"attestationObject\":\"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjkSZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NBAAADlwAAAAAAAAAAAAAAAAAAAAAAYPzdjO7fUHtq8EuGrDWdeSOE4Xfp5F6MOv5cg0-glETN4A9bAKtBcjJ3_DQzgETFjI4zYD33h6T1j9EPJ5Mfr-6TUbkdCMER5L2XmcWld0JdxxYoAclTobgdzgqtnpvFXqUBAgMmIAEhWCBwm_S46LuncSKubWLGS7236xBQyY-Ptg0dTKpOmddRMCJYIG02ZJischNpyUqMXRdiJfBW2kDmG3TROzKzHHBHmLlp\",\"clientDataJSON\":\"eyJjaGFsbGVuZ2UiOiJlTW1Ca0gxQ05KZzFsbGRQb3ZXQUN6R0pMZUpYRHZndmViUXIycDRxdWNVIiwib3JpZ2luIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6MzM0NDMiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0\"}}": ""
}
*/

}
4 changes: 3 additions & 1 deletion cmd/keymasterd/userProfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (u *userProfile) WebAuthnIcon() string {

// This function is needed to create a unified view of all webauthn credentials
func (u *userProfile) WebAuthnCredentials() []webauthn.Credential {
logger.Debugf(3, "top of profile.WebAuthnCredentials ")
var rvalue []webauthn.Credential
for _, authData := range u.WebauthnData {
if !authData.Enabled {
Expand Down Expand Up @@ -81,6 +82,7 @@ func (u *userProfile) WebAuthnCredentials() []webauthn.Credential {

// This function will eventualy also do migration of credential data if needed
func (u *userProfile) FixupCredential(username string, displayname string) {
logger.Debugf(3, "top of profile.FixupCredential ")
if u.DisplayName == "" {
u.DisplayName = displayname
}
Expand All @@ -98,7 +100,7 @@ func (u *userProfile) FixupCredential(username string, displayname string) {
}
}

/// next are not actually from there... but make it simpler
// next are not actually from there... but make it simpler
func (u *userProfile) AddWebAuthnCredential(cred webauthn.Credential) error {
index := time.Now().Unix()
authData := webauthAuthData{
Expand Down

0 comments on commit a40a44c

Please sign in to comment.