mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 09:21:39 +00:00
338 lines
9.7 KiB
Plaintext
338 lines
9.7 KiB
Plaintext
package auth
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/sonr-io/sonr/x/did/types"
|
|
)
|
|
|
|
// Mock DIDClient for testing
|
|
type mockDIDClient struct {
|
|
credentials []*types.WebAuthnCredential
|
|
didDoc *types.DIDDocument
|
|
error error
|
|
}
|
|
|
|
func (m *mockDIDClient) QueryCredentials(ctx context.Context, did string) ([]*types.WebAuthnCredential, error) {
|
|
if m.error != nil {
|
|
return nil, m.error
|
|
}
|
|
return m.credentials, nil
|
|
}
|
|
|
|
func (m *mockDIDClient) QueryCredential(ctx context.Context, did, credentialID string) (*types.WebAuthnCredential, error) {
|
|
if m.error != nil {
|
|
return nil, m.error
|
|
}
|
|
for _, cred := range m.credentials {
|
|
if cred.CredentialId == credentialID {
|
|
return cred, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("key not found")
|
|
}
|
|
|
|
func (m *mockDIDClient) UpdateCredential(ctx context.Context, did string, credential *types.WebAuthnCredential) error {
|
|
if m.error != nil {
|
|
return m.error
|
|
}
|
|
for i, cred := range m.credentials {
|
|
if cred.CredentialId == credential.CredentialId {
|
|
m.credentials[i] = credential
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("key not found")
|
|
}
|
|
|
|
func (m *mockDIDClient) RevokeCredential(ctx context.Context, did, credentialID string) error {
|
|
if m.error != nil {
|
|
return m.error
|
|
}
|
|
for i, cred := range m.credentials {
|
|
if cred.CredentialId == credentialID {
|
|
// Remove from slice
|
|
m.credentials = append(m.credentials[:i], m.credentials[i+1:]...)
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("key not found")
|
|
}
|
|
|
|
func (m *mockDIDClient) QueryDIDDocument(ctx context.Context, did string) (*types.DIDDocument, error) {
|
|
if m.error != nil {
|
|
return nil, m.error
|
|
}
|
|
return m.didDoc, nil
|
|
}
|
|
|
|
func (m *mockDIDClient) AuthenticateWithDID(ctx context.Context, did string, assertion []byte) (bool, error) {
|
|
if m.error != nil {
|
|
return false, m.error
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (m *mockDIDClient) SignTransaction(ctx context.Context, did string, txBytes []byte, credentialID string) ([]byte, error) {
|
|
if m.error != nil {
|
|
return nil, m.error
|
|
}
|
|
// Mock signature
|
|
return []byte("mock_signature"), nil
|
|
}
|
|
|
|
// Helper function to create test credentials
|
|
func createTestCredential(id string) *types.WebAuthnCredential {
|
|
return &types.WebAuthnCredential{
|
|
CredentialId: id,
|
|
RawId: base64.RawURLEncoding.EncodeToString([]byte(id)),
|
|
ClientDataJson: `{"type":"webauthn.create","challenge":"test","origin":"http://localhost"}`,
|
|
AttestationObject: base64.RawURLEncoding.EncodeToString([]byte("test_attestation")),
|
|
PublicKey: []byte("test_public_key"),
|
|
Algorithm: -7, // ES256
|
|
Origin: "http://localhost",
|
|
CreatedAt: 1234567890,
|
|
}
|
|
}
|
|
|
|
func TestWebAuthnClient_CompleteRegistration(t *testing.T) {
|
|
client := &webAuthnClient{
|
|
origin: "http://localhost",
|
|
rpID: "localhost",
|
|
}
|
|
|
|
challenge := &RegistrationChallenge{
|
|
Challenge: []byte("test_challenge"),
|
|
User: &User{
|
|
ID: []byte("test_user"),
|
|
Name: "Test User",
|
|
DisplayName: "Test",
|
|
},
|
|
}
|
|
|
|
// Create valid client data JSON
|
|
clientData := map[string]any{
|
|
"type": "webauthn.create",
|
|
"challenge": challenge.Challenge,
|
|
"origin": "http://localhost",
|
|
}
|
|
clientDataJSON, _ := json.Marshal(clientData)
|
|
|
|
response := &AuthenticatorAttestationResponse{
|
|
ClientDataJSON: clientDataJSON,
|
|
AttestationObject: []byte("test_attestation"),
|
|
}
|
|
|
|
// Test successful registration
|
|
cred, err := client.CompleteRegistration(context.Background(), challenge, response)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, cred)
|
|
|
|
// Test with invalid client data
|
|
response.ClientDataJSON = []byte("invalid_json")
|
|
_, err = client.CompleteRegistration(context.Background(), challenge, response)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_CompleteAuthentication(t *testing.T) {
|
|
credential := createTestCredential("test_cred_1")
|
|
client := &webAuthnClient{
|
|
origin: "http://localhost",
|
|
rpID: "localhost",
|
|
}
|
|
|
|
challenge := &AuthenticationChallenge{
|
|
Challenge: []byte("test_challenge"),
|
|
}
|
|
|
|
// Create valid client data JSON
|
|
clientData := map[string]any{
|
|
"type": "webauthn.get",
|
|
"challenge": challenge.Challenge,
|
|
"origin": "http://localhost",
|
|
}
|
|
clientDataJSON, _ := json.Marshal(clientData)
|
|
|
|
response := &AuthenticatorAssertionResponse{
|
|
ClientDataJSON: clientDataJSON,
|
|
AuthenticatorData: []byte("test_auth_data"),
|
|
Signature: []byte("test_signature"),
|
|
UserHandle: []byte("test_user"),
|
|
}
|
|
|
|
// Test successful authentication
|
|
result, err := client.CompleteAuthentication(context.Background(), challenge, response, "test_cred_1")
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.True(t, result.Verified)
|
|
|
|
// Test with wrong origin
|
|
clientData["origin"] = "http://evil.com"
|
|
clientDataJSON, _ = json.Marshal(clientData)
|
|
response.ClientDataJSON = base64.RawURLEncoding.EncodeToString(clientDataJSON)
|
|
_, err = client.CompleteAuthentication(context.Background(), challenge, response, "test_cred_1")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_ListCredentials(t *testing.T) {
|
|
cred1 := createTestCredential("cred1")
|
|
cred2 := createTestCredential("cred2")
|
|
|
|
client := &webAuthnClient{
|
|
didClient: &mockDIDClient{
|
|
credentials: []*types.WebAuthnCredential{cred1, cred2},
|
|
},
|
|
}
|
|
|
|
// Test successful list
|
|
creds, err := client.ListCredentials(context.Background(), "did:test:123")
|
|
require.NoError(t, err)
|
|
assert.Len(t, creds, 2)
|
|
assert.Equal(t, "cred1", creds[0].CredentialId)
|
|
assert.Equal(t, "cred2", creds[1].CredentialId)
|
|
|
|
// Test with error
|
|
client.didClient = &mockDIDClient{error: assert.AnError}
|
|
_, err = client.ListCredentials(context.Background(), "did:test:123")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_GetCredential(t *testing.T) {
|
|
cred := createTestCredential("test_cred")
|
|
|
|
client := &webAuthnClient{
|
|
didClient: &mockDIDClient{
|
|
credentials: []*types.WebAuthnCredential{cred},
|
|
},
|
|
}
|
|
|
|
// Test successful get
|
|
retrieved, err := client.GetCredential(context.Background(), "did:test:123", "test_cred")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, cred.CredentialId, retrieved.CredentialId)
|
|
|
|
// Test credential not found
|
|
_, err = client.GetCredential(context.Background(), "did:test:123", "non_existent")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_UpdateCredential(t *testing.T) {
|
|
cred := createTestCredential("test_cred")
|
|
|
|
client := &webAuthnClient{
|
|
didClient: &mockDIDClient{
|
|
credentials: []*types.WebAuthnCredential{cred},
|
|
},
|
|
}
|
|
|
|
// Update the credential
|
|
updatedCred := createTestCredential("test_cred")
|
|
updatedCred.Origin = "https://updated.example.com"
|
|
|
|
err := client.UpdateCredential(context.Background(), "did:test:123", updatedCred)
|
|
require.NoError(t, err)
|
|
|
|
// Verify update
|
|
mock := client.didClient.(*mockDIDClient)
|
|
assert.Equal(t, "https://updated.example.com", mock.credentials[0].Origin)
|
|
|
|
// Test update non-existent credential
|
|
nonExistent := createTestCredential("non_existent")
|
|
err = client.UpdateCredential(context.Background(), "did:test:123", nonExistent)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_RevokeCredential(t *testing.T) {
|
|
cred1 := createTestCredential("cred1")
|
|
cred2 := createTestCredential("cred2")
|
|
|
|
client := &webAuthnClient{
|
|
didClient: &mockDIDClient{
|
|
credentials: []*types.WebAuthnCredential{cred1, cred2},
|
|
},
|
|
}
|
|
|
|
// Revoke first credential
|
|
err := client.RevokeCredential(context.Background(), "did:test:123", "cred1")
|
|
require.NoError(t, err)
|
|
|
|
// Verify revocation
|
|
mock := client.didClient.(*mockDIDClient)
|
|
assert.Len(t, mock.credentials, 1)
|
|
assert.Equal(t, "cred2", mock.credentials[0].CredentialId)
|
|
|
|
// Test revoke non-existent credential
|
|
err = client.RevokeCredential(context.Background(), "did:test:123", "non_existent")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_AuthenticateWithDID(t *testing.T) {
|
|
client := &webAuthnClient{
|
|
origin: "http://localhost",
|
|
didClient: &mockDIDClient{
|
|
didDoc: &types.DIDDocument{
|
|
Id: "did:test:123",
|
|
},
|
|
},
|
|
}
|
|
|
|
assertion := &AuthenticationAssertion{
|
|
CredentialID: "test_cred",
|
|
ClientDataJSON: base64.RawURLEncoding.EncodeToString([]byte(`{"type":"webauthn.get"}`)),
|
|
AuthenticatorData: base64.RawURLEncoding.EncodeToString([]byte("auth_data")),
|
|
Signature: base64.RawURLEncoding.EncodeToString([]byte("signature")),
|
|
UserHandle: base64.RawURLEncoding.EncodeToString([]byte("user")),
|
|
}
|
|
|
|
// Test successful authentication
|
|
result, err := client.AuthenticateWithDID(context.Background(), "did:test:123", assertion)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.True(t, result.Success)
|
|
assert.Equal(t, "test_cred", result.CredentialId)
|
|
|
|
// Test with error
|
|
client.didClient = &mockDIDClient{error: assert.AnError}
|
|
_, err = client.AuthenticateWithDID(context.Background(), "did:test:123", assertion)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_SignWithWebAuthn(t *testing.T) {
|
|
client := &webAuthnClient{
|
|
didClient: &mockDIDClient{},
|
|
}
|
|
|
|
txData := []byte("transaction_data")
|
|
|
|
// Test successful signing
|
|
sig, err := client.SignWithWebAuthn(context.Background(), "did:test:123", txData, "test_cred")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []byte("mock_signature"), sig)
|
|
|
|
// Test with error
|
|
client.didClient = &mockDIDClient{error: assert.AnError}
|
|
_, err = client.SignWithWebAuthn(context.Background(), "did:test:123", txData, "test_cred")
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestWebAuthnClient_BindCredential(t *testing.T) {
|
|
client := &webAuthnClient{}
|
|
|
|
cred := createTestCredential("test_cred")
|
|
|
|
// Test that BindCredential returns the existing implementation message
|
|
result, err := client.BindCredential(context.Background(), "did:test:123", cred)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, result)
|
|
assert.Equal(t, "test_cred", result.CredentialId)
|
|
|
|
// The actual binding logic would be implemented in a later phase
|
|
// For now, it just returns the credential as-is
|
|
} |