mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 19:44:21 +00:00
bd5defa96a
This fix provides a possibility to pass a domain on the session, which will be used (as rpID) to create a passkey / u2f assertion and attestation. This is useful in cases where the login UI is served under a different domain / origin than the ZITADEL API.
85 lines
2.8 KiB
Go
85 lines
2.8 KiB
Go
package command
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
|
)
|
|
|
|
type humanPasskeys struct {
|
|
human *domain.Human
|
|
tokens []*domain.WebAuthNToken
|
|
}
|
|
|
|
func (s *SessionCommands) getHumanPasskeys(ctx context.Context) (*humanPasskeys, error) {
|
|
humanWritemodel, err := s.gethumanWriteModel(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tokenReadModel, err := s.getHumanPasswordlessTokenReadModel(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &humanPasskeys{
|
|
human: writeModelToHuman(humanWritemodel),
|
|
tokens: readModelToPasswordlessTokens(tokenReadModel),
|
|
}, nil
|
|
}
|
|
|
|
func (s *SessionCommands) getHumanPasswordlessTokenReadModel(ctx context.Context) (*HumanPasswordlessTokensReadModel, error) {
|
|
tokenReadModel := NewHumanPasswordlessTokensReadModel(s.sessionWriteModel.UserID, s.sessionWriteModel.ResourceOwner)
|
|
err := s.eventstore.FilterToQueryReducer(ctx, tokenReadModel)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return tokenReadModel, nil
|
|
}
|
|
|
|
func (c *Commands) CreatePasskeyChallenge(userVerification domain.UserVerificationRequirement, dst json.Unmarshaler) SessionCommand {
|
|
return func(ctx context.Context, cmd *SessionCommands) error {
|
|
humanPasskeys, err := cmd.getHumanPasskeys(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
webAuthNLogin, err := c.webauthnConfig.BeginLogin(ctx, humanPasskeys.human, userVerification, cmd.sessionWriteModel.Domain, humanPasskeys.tokens...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = json.Unmarshal(webAuthNLogin.CredentialAssertionData, dst); err != nil {
|
|
return caos_errs.ThrowInternal(err, "COMMAND-Yah6A", "Errors.Internal")
|
|
}
|
|
|
|
cmd.sessionWriteModel.PasskeyChallenged(ctx, webAuthNLogin.Challenge, webAuthNLogin.AllowedCredentialIDs, webAuthNLogin.UserVerification)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (c *Commands) CheckPasskey(credentialAssertionData json.Marshaler) SessionCommand {
|
|
return func(ctx context.Context, cmd *SessionCommands) error {
|
|
credentialAssertionData, err := json.Marshal(credentialAssertionData)
|
|
if err != nil {
|
|
return caos_errs.ThrowInvalidArgument(err, "COMMAND-ohG2o", "todo")
|
|
}
|
|
humanPasskeys, err := cmd.getHumanPasskeys(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
webAuthN, err := cmd.sessionWriteModel.PasskeyChallenge.WebAuthNLogin(humanPasskeys.human, credentialAssertionData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
keyID, signCount, err := c.webauthnConfig.FinishLogin(ctx, humanPasskeys.human, webAuthN, credentialAssertionData, humanPasskeys.tokens...)
|
|
if err != nil && keyID == nil {
|
|
return err
|
|
}
|
|
_, token := domain.GetTokenByKeyID(humanPasskeys.tokens, keyID)
|
|
if token == nil {
|
|
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Aej7i", "Errors.User.WebAuthN.NotFound")
|
|
}
|
|
cmd.sessionWriteModel.PasskeyChecked(ctx, cmd.now(), token.WebAuthNTokenID, signCount)
|
|
return nil
|
|
}
|
|
}
|