Skip to content

Commit

Permalink
test: add test case for android auth
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Oct 28, 2024
1 parent 3a1503c commit ee8e5fc
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 15 deletions.
7 changes: 5 additions & 2 deletions identity/credentials_webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,14 @@ func (c *CredentialWebAuthn) ToWebAuthn() *webauthn.Credential {
PublicKey: c.PublicKey,
AttestationType: c.AttestationType,
Transport: c.Transport,
Authenticator: webauthn.Authenticator{
}

if c.Authenticator != nil {
wc.Authenticator = webauthn.Authenticator{
AAGUID: c.Authenticator.AAGUID,
SignCount: c.Authenticator.SignCount,
CloneWarning: c.Authenticator.CloneWarning,
},
}
}

if c.Flags != nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"passkey_session_data": {
"challenge": "mFtAwmtDDdwcO6200I2H6oWjzOiF21lZhQVlrC4tdaU",
"user_id": "d29OeDNJVjdYR2NRa09RVHhNVG1ZbHE1ejBDYzM1dGV3UWxFT25yaUJKcTUyb0VOR0pUMk5PeXExRXp3Z2M2dg",
"userVerification": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"id": "mK2RV0b2NUGDsj8QqH0XtQ",
"rawId": "mK2RV0b2NUGDsj8QqH0XtQ",
"response": {
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUJYVxRmHaAcJuz7n2X5FJILFPwxIhVpoURyBRglMxnFpdAAAAAOqbjWZNAR0hPOS2tIy1ddQAEJitkVdG9jVBg7I_EKh9F7WlAQIDJiABIVggjEkfDDjIm8yAYfth4u0EV7ApX4kclQONhpK5BLc7W6wiWCCHiHhRNqf8Qhc7bjoIFTqw4lafiC7yrXvojU_WMNcutA",
"clientDataJson": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibUZ0QXdtdEREZHdjTzYyMDBJMkg2b1dqek9pRjIxbFpoUVZsckM0dGRhVSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOlMyUmZOWWdKbVFpS2dkNi1zZGJqVzdwaGNMX09UUDR2R0U4TDUxUTJHQjAiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20udHJwLmFuZC5wZXJzb25hbC5xbCJ9"
},
"type": "public-key"
}
58 changes: 53 additions & 5 deletions selfservice/strategy/passkey/passkey_registration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"net/url"
"testing"

"github.com/ory/x/assertx"

"github.com/ory/kratos/selfservice/flow"

"github.com/stretchr/testify/assert"
Expand All @@ -28,12 +30,21 @@ import (
var (
flows = []string{"spa", "browser"}

//go:embed fixtures/registration/success/response.json
//go:embed fixtures/registration/success/browser/response.json
registrationFixtureSuccessResponse []byte
//go:embed fixtures/registration/success/internal_context.json
registrationFixtureSuccessInternalContext []byte

//go:embed fixtures/registration/success/browser/internal_context.json
registrationFixtureSuccessBrowserInternalContext []byte

//go:embed fixtures/registration/success/android/response.json
registrationFixtureSuccessAndroidResponse []byte

//go:embed fixtures/registration/success/android/internal_context.json
registrationFixtureSuccessAndroidInternalContext []byte

//go:embed fixtures/registration/failure/internal_context_missing_user_id.json
registrationFixtureFailureInternalContextMissingUserID []byte

//go:embed fixtures/registration/failure/internal_context_wrong_user_id.json
registrationFixtureFailureInternalContextWrongUserID []byte
)
Expand Down Expand Up @@ -180,7 +191,7 @@ func TestRegistration(t *testing.T) {

for _, f := range flows {
t.Run("type="+f, func(t *testing.T) {
actual, _, _ := fix.submitPasskeyRegistration(t, f, testhelpers.NewClientWithCookies(t), values)
actual, _, _ := fix.submitPasskeyBrowserRegistration(t, f, testhelpers.NewClientWithCookies(t), values)
assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual)
assert.Contains(t, gjson.Get(actual, "ui.action").String(), fix.publicTS.URL+registration.RouteSubmitFlow, "%s", actual)
registrationhelpers.CheckFormContent(t, []byte(actual), node.PasskeyRegister, "csrf_token", "traits.username", "traits.foobar")
Expand Down Expand Up @@ -220,7 +231,7 @@ func TestRegistration(t *testing.T) {

for _, f := range flows {
t.Run("type="+f, func(t *testing.T) {
actual, _, _ := fix.submitPasskeyRegistration(t, f, testhelpers.NewClientWithCookies(t), values,
actual, _, _ := fix.submitPasskeyBrowserRegistration(t, f, testhelpers.NewClientWithCookies(t), values,
withInternalContext(sqlxx.JSONRawMessage(tc.internalContext)))
if flowIsSPA(f) {
assert.Equal(t, "Internal Server Error", gjson.Get(actual, "error.status").String(), "%s", actual)
Expand Down Expand Up @@ -305,6 +316,43 @@ func TestRegistration(t *testing.T) {
}
})

t.Run("case=should create the identity when using android", func(t *testing.T) {
fix.useRedirNoSessionTS()
t.Cleanup(fix.useRedirTS)
fix.disableSessionAfterRegistration()

fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPID, "www.troweprice.com")
fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPOrigins, []string{"android:apk-key-hash:S2RfNYgJmQiKgd6-sdbjW7phcL_OTP4vGE8L51Q2GB0"})

for _, f := range flows {
t.Run("type="+f, func(t *testing.T) {
email := f + "-" + testhelpers.RandomEmail()
userID := f + "-user-" + randx.MustString(8, randx.AlphaNum)

expectReturnTo := fix.redirNoSessionTS.URL + "/registration-return-ts"
actual, res, _ := fix.submitPasskeyAndroidRegistration(t, f, testhelpers.NewClientWithCookies(t), func(v url.Values) {
values(email)(v)
v.Set(node.PasskeyRegister, string(registrationFixtureSuccessAndroidResponse))
}, withUserID(userID))

if f == "spa" {
expectReturnTo = fix.publicTS.URL
assert.Equal(t, email, gjson.Get(actual, "identity.traits.username").String(), "%s", actual)
assert.False(t, gjson.Get(actual, "session").Exists(), "because the registration yielded no session, the user is not expected to be signed in: %s", actual)
} else {
assert.Equal(t, "null\n", actual, "because the registration yielded no session, the user is not expected to be signed in: %s", actual)
}

assert.Contains(t, res.Request.URL.String(), expectReturnTo, "%+v\n\t%s", res.Request, assertx.PrettifyJSONPayload(t, actual))

i, _, err := fix.reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(fix.ctx, identity.CredentialsTypePasskey, userID)
require.NoError(t, err)
assert.Equal(t, "aal1", i.InternalAvailableAAL.String)
assert.Equal(t, email, gjson.GetBytes(i.Traits, "username").String(), "%s", actual)
})
}
})

t.Run("case=should accept valid transient payload", func(t *testing.T) {
fix.useRedirNoSessionTS()
t.Cleanup(fix.useRedirTS)
Expand Down
33 changes: 25 additions & 8 deletions selfservice/strategy/passkey/testfixture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,6 @@ type submitPasskeyOpt struct {
internalContext sqlxx.JSONRawMessage
}

func newSubmitPasskeyOpt() *submitPasskeyOpt {
return &submitPasskeyOpt{
internalContext: registrationFixtureSuccessInternalContext,
}
}

type submitPasskeyOption func(o *submitPasskeyOpt)

func withUserID(id string) submitPasskeyOption {
Expand All @@ -261,14 +255,37 @@ func withInternalContext(ic sqlxx.JSONRawMessage) submitPasskeyOption {
}
}

func (fix *fixture) submitPasskeyBrowserRegistration(
t *testing.T,
flowType string,
client *http.Client,
cb func(values url.Values),
opts ...submitPasskeyOption,
) (string, *http.Response, *kratos.RegistrationFlow) {
return fix.submitPasskeyRegistration(t, flowType, client, cb, append([]submitPasskeyOption{withInternalContext(registrationFixtureSuccessBrowserInternalContext)}, opts...)...)
}

func (fix *fixture) submitPasskeyAndroidRegistration(
t *testing.T,
flowType string,
client *http.Client,
cb func(values url.Values),
opts ...submitPasskeyOption,
) (string, *http.Response, *kratos.RegistrationFlow) {
return fix.submitPasskeyRegistration(t, flowType, client, cb,
append([]submitPasskeyOption{withInternalContext(
registrationFixtureSuccessAndroidInternalContext,
)}, opts...)...)
}

func (fix *fixture) submitPasskeyRegistration(
t *testing.T,
flowType string,
client *http.Client,
cb func(values url.Values),
opts ...submitPasskeyOption,
) (string, *http.Response, *kratos.RegistrationFlow) {
o := newSubmitPasskeyOpt()
o := &submitPasskeyOpt{}
for _, fn := range opts {
fn(o)
}
Expand Down Expand Up @@ -302,7 +319,7 @@ func (fix *fixture) submitPasskeyRegistration(
}

func (fix *fixture) makeRegistration(t *testing.T, flowType string, values func(v url.Values), opts ...submitPasskeyOption) (actual string, res *http.Response, fetchedFlow *registration.Flow) {
actual, res, actualFlow := fix.submitPasskeyRegistration(t, flowType, testhelpers.NewClientWithCookies(t), values, opts...)
actual, res, actualFlow := fix.submitPasskeyBrowserRegistration(t, flowType, testhelpers.NewClientWithCookies(t), values, opts...)
fetchedFlow, err := fix.reg.RegistrationFlowPersister().GetRegistrationFlow(fix.ctx, uuid.FromStringOrNil(actualFlow.Id))
require.NoError(t, err)

Expand Down

0 comments on commit ee8e5fc

Please sign in to comment.