From 8c3b5adaed8b5e6e9cc87d6ccad9d24effaafab9 Mon Sep 17 00:00:00 2001 From: Patryk Kalinowski Date: Wed, 19 Jun 2024 19:22:30 +0300 Subject: [PATCH 1/4] rpc/auth: implement guest.AuthProvider --- proto/identity.go | 6 ++ rpc/auth/guest/provider.go | 119 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 rpc/auth/guest/provider.go diff --git a/proto/identity.go b/proto/identity.go index 7dd9f27d..418f1019 100644 --- a/proto/identity.go +++ b/proto/identity.go @@ -7,6 +7,8 @@ import ( func (id Identity) String() string { switch id.Type { + case IdentityType_Guest: + return string(id.Type) + ":" + id.Subject case IdentityType_OIDC: return string(id.Type) + ":" + id.Issuer + "#" + id.Subject case IdentityType_Email: @@ -23,6 +25,10 @@ func (id *Identity) FromString(s string) error { } switch IdentityType(parts[0]) { + case IdentityType_Guest: + id.Type = IdentityType_Guest + id.Subject = parts[1] + case IdentityType_OIDC: oidcParts := strings.SplitN(parts[1], "#", 2) if len(oidcParts) != 2 { diff --git a/rpc/auth/guest/provider.go b/rpc/auth/guest/provider.go new file mode 100644 index 00000000..4fc228d7 --- /dev/null +++ b/rpc/auth/guest/provider.go @@ -0,0 +1,119 @@ +package guest + +import ( + "context" + "fmt" + "io" + "time" + + "github.com/0xsequence/ethkit/go-ethereum/common/hexutil" + ethcrypto "github.com/0xsequence/ethkit/go-ethereum/crypto" + "github.com/0xsequence/go-sequence/intents" + "github.com/0xsequence/waas-authenticator/proto" + "github.com/0xsequence/waas-authenticator/rpc/attestation" + "github.com/0xsequence/waas-authenticator/rpc/auth" + "github.com/0xsequence/waas-authenticator/rpc/tenant" +) + +type AuthProvider struct{} + +func NewAuthProvider() auth.Provider { + return &AuthProvider{} +} + +func (AuthProvider) IsEnabled(tenant *proto.TenantData) bool { + return tenant.AuthConfig.Guest.Enabled == true +} + +func (p AuthProvider) InitiateAuth( + ctx context.Context, + verifCtx *proto.VerificationContext, + verifier string, + sessionID string, + storeFn auth.StoreVerificationContextFn, +) (*intents.IntentResponseAuthInitiated, error) { + att := attestation.FromContext(ctx) + tnt := tenant.FromContext(ctx) + + if verifier != sessionID { + return nil, fmt.Errorf("invalid session ID") + } + + // client salt is sent back to the client in the intent response + clientSalt, err := randomHex(att, 12) + if err != nil { + return nil, err + } + // server salt is sent to the WaaS API and stored in the auth session + serverSalt, err := randomHex(att, 12) + if err != nil { + return nil, err + } + + // clientAnswer is the value that we expect the client to produce + clientAnswer := hexutil.Encode(ethcrypto.Keccak256([]byte(clientSalt + verifier))) + + // serverAnswer is the value we compare the answer against during verification + serverAnswer := hexutil.Encode(ethcrypto.Keccak256([]byte(serverSalt + clientAnswer))) + + verifCtx = &proto.VerificationContext{ + ProjectID: tnt.ProjectID, + SessionID: sessionID, + IdentityType: proto.IdentityType_Guest, + Verifier: verifier, + Challenge: &serverSalt, // the SERVER salt is a challenge in server's context + Answer: &serverAnswer, // the final answer, after hashing clientAnswer with serverSalt + ExpiresAt: time.Now().Add(5 * time.Minute), + } + if err := storeFn(ctx, verifCtx); err != nil { + return nil, err + } + + // Client should combine the challenge from the response with the session ID and hash it. + // The resulting value is the clientAnswer that is then send with the openSession intent and passed to Verify. + res := &intents.IntentResponseAuthInitiated{ + SessionID: verifCtx.SessionID, + IdentityType: intents.IdentityType_Guest, + ExpiresIn: int(time.Now().Sub(verifCtx.ExpiresAt).Seconds()), + Challenge: &clientSalt, // the CLIENT salt is a challenge in client's context + } + return res, nil +} + +func (p AuthProvider) Verify(ctx context.Context, verifCtx *proto.VerificationContext, sessionID string, answer string) (proto.Identity, error) { + if verifCtx == nil { + return proto.Identity{}, fmt.Errorf("verification context not found") + } + + if verifCtx.Challenge == nil || verifCtx.Answer == nil { + return proto.Identity{}, fmt.Errorf("verification context did not have challenge/answer") + } + + if verifCtx.Verifier != sessionID { + return proto.Identity{}, fmt.Errorf("invalid session ID") + } + + // challenge here is the server salt; combined with the client's answer and hashed it produces the serverAnswer + serverAnswer := hexutil.Encode(ethcrypto.Keccak256([]byte(*verifCtx.Challenge + answer))) + if serverAnswer != *verifCtx.Answer { + return proto.Identity{}, fmt.Errorf("incorrect answer") + } + + ident := proto.Identity{ + Type: proto.IdentityType_Guest, + Subject: sessionID, + } + return ident, nil +} + +func (p AuthProvider) ValidateTenant(ctx context.Context, tenant *proto.TenantData) error { + return nil +} + +func randomHex(source io.Reader, n int) (string, error) { + b := make([]byte, n) + if _, err := source.Read(b); err != nil { + return "", err + } + return hexutil.Encode(b), nil +} From bae37ba8900b0ef63a118f3dc193c48eca01a3aa Mon Sep 17 00:00:00 2001 From: Patryk Kalinowski Date: Wed, 19 Jun 2024 19:22:48 +0300 Subject: [PATCH 2/4] rpc/auth: implement oidc.AuthProvider --- rpc/auth/oidc/provider.go | 216 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 rpc/auth/oidc/provider.go diff --git a/rpc/auth/oidc/provider.go b/rpc/auth/oidc/provider.go new file mode 100644 index 00000000..c2db5add --- /dev/null +++ b/rpc/auth/oidc/provider.go @@ -0,0 +1,216 @@ +package oidc + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/0xsequence/ethkit/go-ethereum/common/hexutil" + ethcrypto "github.com/0xsequence/ethkit/go-ethereum/crypto" + "github.com/0xsequence/go-sequence/intents" + "github.com/0xsequence/waas-authenticator/proto" + "github.com/0xsequence/waas-authenticator/rpc/auth" + "github.com/0xsequence/waas-authenticator/rpc/tenant" + "github.com/0xsequence/waas-authenticator/rpc/tracing" + "github.com/goware/cachestore" + "github.com/goware/cachestore/cachestorectl" + "github.com/lestrrat-go/jwx/v2/jwk" + "github.com/lestrrat-go/jwx/v2/jws" + "github.com/lestrrat-go/jwx/v2/jwt" + "golang.org/x/sync/errgroup" +) + +type AuthProvider struct { + client HTTPClient + store cachestore.Store[jwk.Key] +} + +func NewAuthProvider(cacheBackend cachestore.Backend, client HTTPClient) (auth.Provider, error) { + if client == nil { + client = http.DefaultClient + } + store, err := cachestorectl.Open[jwk.Key](cacheBackend) + if err != nil { + return nil, err + } + return &AuthProvider{ + client: client, + store: store, + }, nil +} + +func (*AuthProvider) IsEnabled(tenant *proto.TenantData) bool { + return len(tenant.OIDCProviders) > 0 +} + +func (p *AuthProvider) InitiateAuth( + ctx context.Context, + verifCtx *proto.VerificationContext, + verifier string, + sessionID string, + storeFn auth.StoreVerificationContextFn, +) (*intents.IntentResponseAuthInitiated, error) { + tnt := tenant.FromContext(ctx) + + if verifCtx != nil { + return nil, fmt.Errorf("cannot reuse an old ID token") + } + + tokHash, expiresAt, err := p.extractVerifier(verifier) + if err != nil { + return nil, err + } + + if time.Now().After(expiresAt) { + return nil, fmt.Errorf("token expired") + } + + answer := tokHash + challenge := fmt.Sprintf("exp=%d", expiresAt.Unix()) + + verifCtx = &proto.VerificationContext{ + ProjectID: tnt.ProjectID, + SessionID: sessionID, + IdentityType: proto.IdentityType_OIDC, + Verifier: verifier, + Answer: &answer, + Challenge: &challenge, + ExpiresAt: expiresAt, + } + if err := storeFn(ctx, verifCtx); err != nil { + return nil, err + } + + res := &intents.IntentResponseAuthInitiated{ + SessionID: verifCtx.SessionID, + IdentityType: intents.IdentityType_OIDC, + ExpiresIn: int(verifCtx.ExpiresAt.Sub(time.Now()).Seconds()), + } + return res, nil +} + +func (p *AuthProvider) Verify(ctx context.Context, verifCtx *proto.VerificationContext, sessionID string, answer string) (ident proto.Identity, err error) { + if verifCtx == nil { + return proto.Identity{}, fmt.Errorf("auth session not found") + } + + tok, err := jwt.Parse([]byte(answer), jwt.WithVerify(false), jwt.WithValidate(false)) + if err != nil { + return proto.Identity{}, fmt.Errorf("parse JWT: %w", err) + } + + issuer := normalizeIssuer(tok.Issuer()) + idp := getOIDCProvider(ctx, issuer) + if idp == nil { + return proto.Identity{}, fmt.Errorf("issuer %q not valid for this tenant", issuer) + } + + expectedHash := hexutil.Encode(ethcrypto.Keccak256([]byte(answer))) + if *verifCtx.Answer != expectedHash { + return proto.Identity{}, fmt.Errorf("invalid token hash") + } + + if err := p.verifyChallenge(tok, *verifCtx.Challenge); err != nil { + return proto.Identity{}, fmt.Errorf("verify challenge: %w", err) + } + + ks := &operationKeySet{ + ctx: ctx, + iss: issuer, + store: p.store, + getKeySet: p.GetKeySet, + } + + if _, err := jws.Verify([]byte(answer), jws.WithKeySet(ks, jws.WithMultipleKeysPerKeyID(false))); err != nil { + return proto.Identity{}, fmt.Errorf("signature verification: %w", err) + } + + validateOptions := []jwt.ValidateOption{ + jwt.WithValidator(withIssuer(idp.Issuer)), + jwt.WithAcceptableSkew(10 * time.Second), + jwt.WithValidator(withAudience(idp.Audience)), + } + + if err := jwt.Validate(tok, validateOptions...); err != nil { + return proto.Identity{}, fmt.Errorf("JWT validation: %w", err) + } + + identity := proto.Identity{ + Type: proto.IdentityType_OIDC, + Issuer: issuer, + Subject: tok.Subject(), + Email: getEmailFromToken(tok), + } + return identity, nil +} + +func (p *AuthProvider) ValidateTenant(ctx context.Context, tenant *proto.TenantData) error { + var wg errgroup.Group + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + for i, provider := range tenant.OIDCProviders { + provider := provider + + if provider.Issuer == "" { + return fmt.Errorf("provider %d: empty issuer", i) + } + + if len(provider.Audience) < 1 { + return fmt.Errorf("provider %d: at least one audience is required", i) + } + + wg.Go(func() error { + if _, err := p.GetKeySet(ctx, provider.Issuer); err != nil { + return err + } + return nil + }) + } + + return wg.Wait() +} + +func (p *AuthProvider) GetKeySet(ctx context.Context, issuer string) (set jwk.Set, err error) { + jwksURL, err := fetchJWKSURL(ctx, p.client, issuer) + if err != nil { + return nil, fmt.Errorf("fetch issuer keys: %w", err) + } + + keySet, err := jwk.Fetch(ctx, jwksURL, jwk.WithHTTPClient(tracing.WrapClientWithContext(ctx, p.client))) + if err != nil { + return nil, fmt.Errorf("fetch issuer keys: %w", err) + } + return keySet, nil +} + +func (p *AuthProvider) extractVerifier(verifier string) (tokHash string, expiresAt time.Time, err error) { + parts := strings.SplitN(verifier, ";", 2) + + tokHash = parts[0] + exp, err := strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return "", time.Time{}, fmt.Errorf("parse exp: %w", err) + } + expiresAt = time.Unix(exp, 0) + + return tokHash, expiresAt, nil +} + +func (p *AuthProvider) verifyChallenge(tok jwt.Token, challenge string) error { + s := strings.TrimPrefix(challenge, "exp=") + exp, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return fmt.Errorf("parse exp: %w", err) + } + expiresAt := time.Unix(exp, 0) + + if !tok.Expiration().Equal(expiresAt) { + return fmt.Errorf("invalid exp claim") + } + + return nil +} From c5d8b0adab0da6a48a62578398aa45a5952a018a Mon Sep 17 00:00:00 2001 From: Patryk Kalinowski Date: Wed, 19 Jun 2024 19:23:03 +0300 Subject: [PATCH 3/4] rpc: make the Guest and OIDC providers available --- rpc/accounts.go | 4 ++++ rpc/rpc.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/rpc/accounts.go b/rpc/accounts.go index 26d30fd9..afbc7f73 100644 --- a/rpc/accounts.go +++ b/rpc/accounts.go @@ -63,6 +63,10 @@ func (s *RPC) federateAccount( return nil, fmt.Errorf("get auth provider: %w", err) } + if intent.Data.IdentityType == intents.IdentityType_Guest { + return nil, fmt.Errorf("cannot federate a guest account") + } + var verifCtx *proto.VerificationContext authID := data.AuthID{ ProjectID: tntData.ProjectID, diff --git a/rpc/rpc.go b/rpc/rpc.go index 7d2e9452..cfe9cb1c 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -20,6 +20,7 @@ import ( "github.com/0xsequence/waas-authenticator/rpc/attestation" "github.com/0xsequence/waas-authenticator/rpc/auth" "github.com/0xsequence/waas-authenticator/rpc/auth/email" + "github.com/0xsequence/waas-authenticator/rpc/auth/guest" "github.com/0xsequence/waas-authenticator/rpc/auth/oidc" "github.com/0xsequence/waas-authenticator/rpc/awscreds" "github.com/0xsequence/waas-authenticator/rpc/tenant" @@ -278,6 +279,10 @@ func makeAuthProviders(client HTTPClient, awsCfg aws.Config, cfg *config.Config) if err != nil { return nil, err } + oidcProvider, err := oidc.NewAuthProvider(cacheBackend, client) + if err != nil { + return nil, err + } sm := secretsmanager.NewFromConfig(awsCfg) builderClient := builder.NewBuilderClient( @@ -286,10 +291,13 @@ func makeAuthProviders(client HTTPClient, awsCfg aws.Config, cfg *config.Config) ) sender := email.NewSESSender(awsCfg, cfg.SES) emailProvider := email.NewAuthProvider(sender, builderClient) + guestProvider := guest.NewAuthProvider() verifiers := map[intents.IdentityType]auth.Provider{ intents.IdentityType_None: auth.NewTracedProvider("oidc.LegacyAuthProvider", legacyVerifier), intents.IdentityType_Email: auth.NewTracedProvider("email.AuthProvider", emailProvider), + intents.IdentityType_OIDC: auth.NewTracedProvider("oidc.AuthProvider", oidcProvider), + intents.IdentityType_Guest: auth.NewTracedProvider("guest.AuthProvider", guestProvider), } return verifiers, nil } From 651fbcb10033943a53232d41cdaf6c2f428321d1 Mon Sep 17 00:00:00 2001 From: Patryk Kalinowski Date: Mon, 24 Jun 2024 16:11:05 +0300 Subject: [PATCH 4/4] rpc: add basic tests for guest and oidc auth --- rpc/auth/guest/provider.go | 2 +- rpc/auth_test.go | 127 +++++++++++++++++++++++++++++++++++++ rpc/helpers_test.go | 48 +++++++++++++- 3 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 rpc/auth_test.go diff --git a/rpc/auth/guest/provider.go b/rpc/auth/guest/provider.go index 4fc228d7..4f1800d6 100644 --- a/rpc/auth/guest/provider.go +++ b/rpc/auth/guest/provider.go @@ -74,7 +74,7 @@ func (p AuthProvider) InitiateAuth( res := &intents.IntentResponseAuthInitiated{ SessionID: verifCtx.SessionID, IdentityType: intents.IdentityType_Guest, - ExpiresIn: int(time.Now().Sub(verifCtx.ExpiresAt).Seconds()), + ExpiresIn: int(verifCtx.ExpiresAt.Sub(time.Now()).Seconds()), Challenge: &clientSalt, // the CLIENT salt is a challenge in client's context } return res, nil diff --git a/rpc/auth_test.go b/rpc/auth_test.go new file mode 100644 index 00000000..9aa03e58 --- /dev/null +++ b/rpc/auth_test.go @@ -0,0 +1,127 @@ +package rpc_test + +import ( + "context" + "net/http" + "net/http/httptest" + "strconv" + "testing" + "time" + + "github.com/0xsequence/ethkit/ethwallet" + "github.com/0xsequence/ethkit/go-ethereum/common/hexutil" + "github.com/0xsequence/ethkit/go-ethereum/crypto" + "github.com/0xsequence/go-sequence/intents" + "github.com/0xsequence/waas-authenticator/proto" + "github.com/goccy/go-json" + "github.com/lestrrat-go/jwx/v2/jwt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGuestAuth(t *testing.T) { + t.Run("Success", func(t *testing.T) { + ctx := context.Background() + + svc := initRPC(t) + tenant, _ := newGuestTenant(t, svc.Enclave) + require.NoError(t, svc.Tenants.Add(ctx, tenant)) + + srv := httptest.NewServer(svc.Handler()) + defer srv.Close() + + c := proto.NewWaasAuthenticatorClient(srv.URL, http.DefaultClient) + header := make(http.Header) + header.Set("X-Sequence-Project", strconv.Itoa(int(tenant.ProjectID))) + ctx, err := proto.WithHTTPRequestHeaders(context.Background(), header) + require.NoError(t, err) + + sessWallet, err := ethwallet.NewWalletFromRandomEntropy() + require.NoError(t, err) + signingSession := intents.NewSessionP256K1(sessWallet) + + initiateAuth := generateSignedIntent(t, intents.IntentName_initiateAuth, intents.IntentDataInitiateAuth{ + SessionID: signingSession.SessionID(), + IdentityType: intents.IdentityType_Guest, + Verifier: signingSession.SessionID(), + }, signingSession) + initRes, err := c.SendIntent(ctx, initiateAuth) + require.NoError(t, err) + assert.Equal(t, proto.IntentResponseCode_authInitiated, initRes.Code) + + b, err := json.Marshal(initRes.Data) + require.NoError(t, err) + var initResData intents.IntentResponseAuthInitiated + require.NoError(t, json.Unmarshal(b, &initResData)) + + answer := crypto.Keccak256([]byte(*initResData.Challenge + signingSession.SessionID())) + registerSession := generateSignedIntent(t, intents.IntentName_openSession, intents.IntentDataOpenSession{ + SessionID: signingSession.SessionID(), + IdentityType: intents.IdentityType_Guest, + Verifier: signingSession.SessionID(), + Answer: hexutil.Encode(answer), + }, signingSession) + sess, registerRes, err := c.RegisterSession(ctx, registerSession, "Friendly name") + require.NoError(t, err) + assert.Equal(t, "Guest:"+signingSession.SessionID(), sess.Identity.String()) + assert.Equal(t, proto.IntentResponseCode_sessionOpened, registerRes.Code) + }) +} + +func TestOIDCAuth(t *testing.T) { + t.Run("Success", func(t *testing.T) { + ctx := context.Background() + + exp := time.Now().Add(120 * time.Second) + tokBuilderFn := func(b *jwt.Builder, url string) { + b.Expiration(exp) + } + + issuer, tok, closeJWKS := issueAccessTokenAndRunJwksServer(t, tokBuilderFn) + defer closeJWKS() + + svc := initRPC(t) + tenant, _ := newTenant(t, svc.Enclave, issuer) + require.NoError(t, svc.Tenants.Add(ctx, tenant)) + + sessWallet, err := ethwallet.NewWalletFromRandomEntropy() + require.NoError(t, err) + signingSession := intents.NewSessionP256K1(sessWallet) + + srv := httptest.NewServer(svc.Handler()) + defer srv.Close() + + c := proto.NewWaasAuthenticatorClient(srv.URL, http.DefaultClient) + header := make(http.Header) + header.Set("X-Sequence-Project", strconv.Itoa(int(tenant.ProjectID))) + ctx, err = proto.WithHTTPRequestHeaders(context.Background(), header) + require.NoError(t, err) + + hashedToken := hexutil.Encode(crypto.Keccak256([]byte(tok))) + verifier := hashedToken + ";" + strconv.Itoa(int(exp.Unix())) + initiateAuth := generateSignedIntent(t, intents.IntentName_initiateAuth, intents.IntentDataInitiateAuth{ + SessionID: signingSession.SessionID(), + IdentityType: intents.IdentityType_OIDC, + Verifier: verifier, + }, signingSession) + initRes, err := c.SendIntent(ctx, initiateAuth) + require.NoError(t, err) + assert.Equal(t, proto.IntentResponseCode_authInitiated, initRes.Code) + + b, err := json.Marshal(initRes.Data) + require.NoError(t, err) + var initResData intents.IntentResponseAuthInitiated + require.NoError(t, json.Unmarshal(b, &initResData)) + + registerSession := generateSignedIntent(t, intents.IntentName_openSession, intents.IntentDataOpenSession{ + SessionID: signingSession.SessionID(), + IdentityType: intents.IdentityType_OIDC, + Verifier: verifier, + Answer: tok, + }, signingSession) + sess, registerRes, err := c.RegisterSession(ctx, registerSession, "Friendly name") + require.NoError(t, err) + assert.Equal(t, "OIDC:"+issuer+"#subject", sess.Identity.String()) + assert.Equal(t, proto.IntentResponseCode_sessionOpened, registerRes.Code) + }) +} diff --git a/rpc/helpers_test.go b/rpc/helpers_test.go index 0cd2001a..a998be4b 100644 --- a/rpc/helpers_test.go +++ b/rpc/helpers_test.go @@ -250,6 +250,49 @@ func newTenant(t *testing.T, enc *enclave.Enclave, issuer string) (*data.Tenant, }, payload } +func newGuestTenant(t *testing.T, enc *enclave.Enclave) (*data.Tenant, *proto.TenantData) { + att, err := enc.GetAttestation(context.Background(), nil) + require.NoError(t, err) + + wallet, err := ethwallet.NewWalletFromRandomEntropy() + require.NoError(t, err) + + projectID := currentProjectID.Add(1) + + userSalt, _ := hexutil.Decode("0xa176de7902ef0781d2c6120cc5fd5add3048e1543f597ef4feae38391d234839") + payload := &proto.TenantData{ + ProjectID: projectID, + PrivateKey: wallet.PrivateKeyHex()[2:], + ParentAddress: common.HexToAddress("0xcF104bc904E4dC1cCe0027aB9F9C905Ad3aE6c21"), + UserSalt: userSalt, + SequenceContext: &proto.MiniSequenceContext{ + Factory: "0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A", + MainModule: "0xfBf8f1A5E00034762D928f46d438B947f5d4065d", + }, + UpgradeCode: "CHANGEME", + WaasAccessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXJ0bmVyX2lkIjozfQ.g2fWwLrKPhTUpLFc7ZM9pMm4kEHGu8haCMzMOOGiqSM", + AllowedOrigins: validation.Origins{"http://localhost"}, + AuthConfig: proto.AuthConfig{ + Guest: proto.AuthGuestConfig{ + Enabled: true, + }, + }, + KMSKeys: []string{"arn:aws:kms:us-east-1:000000000000:key/27ebbde0-49d2-4cb6-ad78-4f2c24fe7b79"}, + } + + encryptedKey, algorithm, ciphertext, err := crypto.EncryptData(context.Background(), att, "27ebbde0-49d2-4cb6-ad78-4f2c24fe7b79", payload) + require.NoError(t, err) + + return &data.Tenant{ + ProjectID: projectID, + Version: 1, + EncryptedKey: encryptedKey, + Algorithm: algorithm, + Ciphertext: ciphertext, + CreatedAt: time.Now(), + }, payload +} + func newAccount(t *testing.T, tnt *data.Tenant, enc *enclave.Enclave, issuer string, wallet *ethwallet.Wallet) *data.Account { att, err := enc.GetAttestation(context.Background(), nil) require.NoError(t, err) @@ -343,8 +386,7 @@ type walletServiceMock struct { } func (w walletServiceMock) InitiateAuth(ctx context.Context, intent *proto_wallet.Intent, answer string, challenge string) (*proto_wallet.IntentResponse, error) { - //TODO implement me - panic("implement me") + return nil, nil } func (w walletServiceMock) InitiateEmailAuth(ctx context.Context, intent *proto_wallet.Intent, answerHash string, salt string) (*proto_wallet.IntentResponse, error) { @@ -522,7 +564,7 @@ func (w *walletServiceMock) RegisterSession(ctx context.Context, userID string, w.registeredUsers[userID] = struct{}{} return &proto_wallet.IntentResponse{ - Code: "openedSession", + Code: string(proto.IntentResponseCode_sessionOpened), }, nil }