mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: implement register Passkey user API v2 (#5873)
* command/crypto: DRY the code - reuse the the algorithm switch to create a secret generator - add a verifyCryptoCode function * command: crypto code tests * migrate webauthn package * finish integration tests with webauthn mock client
This commit is contained in:
36
internal/webauthn/client.go
Normal file
36
internal/webauthn/client.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package webauthn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/descope/virtualwebauthn"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
rp virtualwebauthn.RelyingParty
|
||||
auth virtualwebauthn.Authenticator
|
||||
credential virtualwebauthn.Credential
|
||||
}
|
||||
|
||||
func NewClient(name, domain, origin string) *Client {
|
||||
rp := virtualwebauthn.RelyingParty{
|
||||
Name: name,
|
||||
ID: domain,
|
||||
Origin: origin,
|
||||
}
|
||||
return &Client{
|
||||
rp: rp,
|
||||
auth: virtualwebauthn.NewAuthenticator(),
|
||||
credential: virtualwebauthn.NewCredential(virtualwebauthn.KeyTypeEC2),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) CreateAttestationResponse(options []byte) ([]byte, error) {
|
||||
parsedAttestationOptions, err := virtualwebauthn.ParseAttestationOptions(string(options))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("webauthn.Client.CreateAttestationResponse: %w", err)
|
||||
}
|
||||
return []byte(virtualwebauthn.CreateAttestationResponse(
|
||||
c.rp, c.auth, c.credential, *parsedAttestationOptions,
|
||||
)), nil
|
||||
}
|
@@ -1,8 +1,9 @@
|
||||
package webauthn
|
||||
|
||||
import (
|
||||
"github.com/duo-labs/webauthn/protocol"
|
||||
"github.com/duo-labs/webauthn/webauthn"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/duo-labs/webauthn/protocol"
|
||||
"github.com/duo-labs/webauthn/webauthn"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -177,9 +177,13 @@ func (w *Config) FinishLogin(ctx context.Context, user *domain.Human, webAuthN *
|
||||
|
||||
func (w *Config) serverFromContext(ctx context.Context) (*webauthn.WebAuthn, error) {
|
||||
instance := authz.GetInstance(ctx)
|
||||
return webauthn.New(&webauthn.Config{
|
||||
webAuthn, err := webauthn.New(&webauthn.Config{
|
||||
RPDisplayName: w.DisplayName,
|
||||
RPID: instance.RequestedDomain(),
|
||||
RPOrigin: http.BuildOrigin(instance.RequestedHost(), w.ExternalSecure),
|
||||
RPOrigins: []string{http.BuildOrigin(instance.RequestedHost(), w.ExternalSecure)},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "WEBAU-UX9ta", "Errors.User.WebAuthN.ServerConfig")
|
||||
}
|
||||
return webAuthn, nil
|
||||
}
|
||||
|
58
internal/webauthn/webauthn_test.go
Normal file
58
internal/webauthn/webauthn_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package webauthn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
func TestConfig_serverFromContext(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *webauthn.WebAuthn
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "webauthn error",
|
||||
args: args{context.Background()},
|
||||
wantErr: caos_errs.ThrowInternal(nil, "WEBAU-UX9ta", "Errors.User.WebAuthN.ServerConfig"),
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
args: args{authz.WithRequestedDomain(context.Background(), "example.com")},
|
||||
want: &webauthn.WebAuthn{
|
||||
Config: &webauthn.Config{
|
||||
RPDisplayName: "DisplayName",
|
||||
RPID: "example.com",
|
||||
RPOrigins: []string{"https://example.com"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &Config{
|
||||
DisplayName: "DisplayName",
|
||||
ExternalSecure: true,
|
||||
}
|
||||
got, err := w.serverFromContext(tt.args.ctx)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
if tt.want != nil {
|
||||
require.NotNil(t, got)
|
||||
assert.Equal(t, tt.want.Config.RPDisplayName, got.Config.RPDisplayName)
|
||||
assert.Equal(t, tt.want.Config.RPID, got.Config.RPID)
|
||||
assert.Equal(t, tt.want.Config.RPOrigins, got.Config.RPOrigins)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user