Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve(passkeys): improve passkey naming #1303

Merged
merged 5 commits into from
Jan 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions backend/Dockerfile
lfleischmann marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the hanko binary
FROM --platform=$BUILDPLATFORM golang:1.20 as builder
FROM --platform=$BUILDPLATFORM golang:1.20 AS builder

ARG TARGETARCH

@@ -28,10 +28,11 @@ COPY build_info build_info/
COPY middleware middleware/
COPY template template/
COPY utils utils/
COPY mapper mapper/

# Build
RUN go generate ./...
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -a -o hanko main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH="$TARGETARCH" go build -a -o hanko main.go

# Use distroless as minimal base image to package hanko binary
# See https://github.com/GoogleContainerTools/distroless for details
7 changes: 4 additions & 3 deletions backend/Dockerfile.debug
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Build the hanko binary
FROM golang:1.20 as builder
FROM golang:1.20 AS builder
WORKDIR /workspace

# Get Delve
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install github.com/go-delve/delve/cmd/dlv@latest
RUN CGO_ENABLED=0 GOOS=linux GOARCH="$TARGETARCH" go install github.com/go-delve/delve/cmd/dlv@latest

COPY go.mod go.mod
COPY go.sum go.sum
@@ -29,10 +29,11 @@ COPY build_info build_info/
COPY middleware middleware/
COPY template template/
COPY utils utils/
COPY mapper mapper/

# Build
RUN go generate ./...
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -gcflags="all=-N -l" -a -o hanko main.go
RUN CGO_ENABLED=0 GOOS=linux GOARCH="$TARGETARCH" go build -gcflags="all=-N -l" -a -o hanko main.go

# Use distroless as minimal base image to package hanko binary
# See https://github.com/GoogleContainerTools/distroless for details
9 changes: 7 additions & 2 deletions backend/cmd/serve/all.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/spf13/cobra"
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/mapper"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/server"
"log"
@@ -15,7 +16,8 @@ import (

func NewServeAllCommand() *cobra.Command {
var (
configFile string
configFile string
authenticatorMetadataFile string
)

cmd := &cobra.Command{
@@ -28,6 +30,8 @@ func NewServeAllCommand() *cobra.Command {
log.Fatal(err)
}

authenticatorMetadata := mapper.LoadAuthenticatorMetadata(&authenticatorMetadataFile)

persister, err := persistence.New(cfg.Database)
if err != nil {
log.Fatal(err)
@@ -37,14 +41,15 @@ func NewServeAllCommand() *cobra.Command {

prometheus := echoprometheus.NewMiddleware("hanko")

go server.StartPublic(cfg, &wg, persister, prometheus)
go server.StartPublic(cfg, &wg, persister, prometheus, authenticatorMetadata)
go server.StartAdmin(cfg, &wg, persister, prometheus)

wg.Wait()
},
}

cmd.Flags().StringVar(&configFile, "config", config.DefaultConfigFilePath, "config file")
cmd.Flags().StringVar(&authenticatorMetadataFile, "auth-meta", "", "authenticator metadata file")

return cmd
}
9 changes: 7 additions & 2 deletions backend/cmd/serve/public.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ package serve
import (
"github.com/spf13/cobra"
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/mapper"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/server"
"log"
@@ -14,7 +15,8 @@ import (

func NewServePublicCommand() *cobra.Command {
var (
configFile string
configFile string
authenticatorMetadataFile string
)

cmd := &cobra.Command{
@@ -27,20 +29,23 @@ func NewServePublicCommand() *cobra.Command {
log.Fatal(err)
}

authenticatorMetadata := mapper.LoadAuthenticatorMetadata(&authenticatorMetadataFile)

persister, err := persistence.New(cfg.Database)
if err != nil {
log.Fatal(err)
}
var wg sync.WaitGroup
wg.Add(1)

go server.StartPublic(cfg, &wg, persister, nil)
go server.StartPublic(cfg, &wg, persister, nil, authenticatorMetadata)

wg.Wait()
},
}

cmd.Flags().StringVar(&configFile, "config", config.DefaultConfigFilePath, "config file")
cmd.Flags().StringVar(&authenticatorMetadataFile, "auth-meta", "", "authenticator metadata file")

return cmd
}
19 changes: 16 additions & 3 deletions backend/config/config.go
Original file line number Diff line number Diff line change
@@ -41,14 +41,27 @@ var (
DefaultConfigFilePath = "./config/config.yaml"
)

func Load(cfgFile *string) (*Config, error) {
func LoadFile(filePath *string, pa koanf.Parser) (*koanf.Koanf, error) {
k := koanf.New(".")
var err error

if filePath == nil || *filePath == "" {
return nil, nil
}

if err := k.Load(file.Provider(*filePath), pa); err != nil {
return nil, fmt.Errorf("failed to load file from '%s': %w", *filePath, err)
}

return k, nil
}

func Load(cfgFile *string) (*Config, error) {
if cfgFile == nil || *cfgFile == "" {
*cfgFile = DefaultConfigFilePath
}

if err = k.Load(file.Provider(*cfgFile), yaml.Parser()); err != nil {
k, err := LoadFile(cfgFile, yaml.Parser())
if err != nil {
if *cfgFile != DefaultConfigFilePath {
return nil, fmt.Errorf("failed to load config from: %s: %w", *cfgFile, err)
}
4 changes: 3 additions & 1 deletion backend/dto/intern/WebauthnCredential.go
Original file line number Diff line number Diff line change
@@ -5,17 +5,19 @@ import (
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/gofrs/uuid"
"github.com/teamhanko/hanko/backend/mapper"
"github.com/teamhanko/hanko/backend/persistence/models"
"time"
)

func WebauthnCredentialToModel(credential *webauthn.Credential, userId uuid.UUID, backupEligible bool, backupState bool) *models.WebauthnCredential {
func WebauthnCredentialToModel(credential *webauthn.Credential, userId uuid.UUID, backupEligible bool, backupState bool, authenticatorMetadata mapper.AuthenticatorMetadata) *models.WebauthnCredential {
now := time.Now().UTC()
aaguid, _ := uuid.FromBytes(credential.Authenticator.AAGUID)
credentialID := base64.RawURLEncoding.EncodeToString(credential.ID)

c := &models.WebauthnCredential{
ID: credentialID,
Name: authenticatorMetadata.GetNameForAaguid(aaguid),
UserId: userId,
PublicKey: base64.RawURLEncoding.EncodeToString(credential.PublicKey),
AttestationType: credential.AttestationType,
8 changes: 4 additions & 4 deletions backend/handler/email_test.go
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ func (s *emailSuite) TestEmailHandler_List() {
err := s.LoadFixtures("../test/fixtures/email")
s.Require().NoError(err)

e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)

jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister())
s.Require().NoError(err)
@@ -172,7 +172,7 @@ func (s *emailSuite) TestEmailHandler_Create() {
cfg.AuditLog.Storage.Enabled = true
cfg.Emails.RequireVerification = currentTest.requiresVerification
cfg.Emails.MaxNumOfAddresses = currentTest.maxNumberOfAddresses
e := NewPublicRouter(&cfg, s.Storage, nil)
e := NewPublicRouter(&cfg, s.Storage, nil, nil)
jwkManager, err := jwk.NewDefaultManager(cfg.Secrets.Keys, s.Storage.GetJwkPersister())
s.Require().NoError(err)
sessionManager, err := session.NewManager(jwkManager, cfg)
@@ -234,7 +234,7 @@ func (s *emailSuite) TestEmailHandler_SetPrimaryEmail() {
err := s.LoadFixtures("../test/fixtures/email")
s.Require().NoError(err)

e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)

jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister())
s.Require().NoError(err)
@@ -278,7 +278,7 @@ func (s *emailSuite) TestEmailHandler_Delete() {
err := s.LoadFixtures("../test/fixtures/email")
s.Require().NoError(err)

e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil)
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)
userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5")

jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister())
4 changes: 2 additions & 2 deletions backend/handler/passcode_test.go
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ func (s *passcodeSuite) TestPasscodeHandler_Init() {
return cfg
}

e := NewPublicRouter(cfg(), s.Storage, nil)
e := NewPublicRouter(cfg(), s.Storage, nil, nil)

emailId := "51b7c175-ceb6-45ba-aae6-0092221c1b84"
unknownEmailId := "83618f24-2db8-4ea2-b370-ac8335f782d8"
@@ -278,7 +278,7 @@ func (s *passcodeSuite) TestPasscodeHandler_Finish() {
sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig)
s.Require().NoError(err)

e := NewPublicRouter(currentTest.cfg(), s.Storage, nil)
e := NewPublicRouter(currentTest.cfg(), s.Storage, nil, nil)

// Setup passcode
err = s.Storage.GetPasscodePersister().Create(currentTest.passcode)
4 changes: 2 additions & 2 deletions backend/handler/password_test.go
Original file line number Diff line number Diff line change
@@ -101,7 +101,7 @@ func (s *passwordSuite) TestPasswordHandler_Set_Create() {
req.AddCookie(cookie)
rec := httptest.NewRecorder()

e := NewPublicRouter(cfg, s.Storage, nil)
e := NewPublicRouter(cfg, s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(currentTest.expectedCode, rec.Code)
@@ -171,7 +171,7 @@ func (s *passwordSuite) TestPasswordHandler_Login() {
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()

e := NewPublicRouter(currentTest.cfg(), s.Storage, nil)
e := NewPublicRouter(currentTest.cfg(), s.Storage, nil, nil)
e.ServeHTTP(rec, req)

if s.Equal(currentTest.expectedCode, rec.Code) {
5 changes: 3 additions & 2 deletions backend/handler/public_router.go
Original file line number Diff line number Diff line change
@@ -11,13 +11,14 @@ import (
"github.com/teamhanko/hanko/backend/dto"
"github.com/teamhanko/hanko/backend/ee/saml"
"github.com/teamhanko/hanko/backend/mail"
"github.com/teamhanko/hanko/backend/mapper"
hankoMiddleware "github.com/teamhanko/hanko/backend/middleware"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/session"
"github.com/teamhanko/hanko/backend/template"
)

func NewPublicRouter(cfg *config.Config, persister persistence.Persister, prometheus echo.MiddlewareFunc) *echo.Echo {
func NewPublicRouter(cfg *config.Config, persister persistence.Persister, prometheus echo.MiddlewareFunc, authenticatorMetadata mapper.AuthenticatorMetadata) *echo.Echo {
e := echo.New()
e.Renderer = template.NewTemplateRenderer()
e.HideBanner = true
@@ -102,7 +103,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet
}

healthHandler := NewHealthHandler()
webauthnHandler, err := NewWebauthnHandler(cfg, persister, sessionManager, auditLogger)
webauthnHandler, err := NewWebauthnHandler(cfg, persister, sessionManager, auditLogger, authenticatorMetadata)
if err != nil {
panic(fmt.Errorf("failed to create public webauthn handler: %w", err))
}
12 changes: 6 additions & 6 deletions backend/handler/token_test.go
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ func (s *tokenSuite) TestToken_Validate_TokenInCookie() {

cfg := s.setupConfig()
cfg.Session.EnableAuthTokenHeader = false
e := NewPublicRouter(cfg, s.Storage, nil)
e := NewPublicRouter(cfg, s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusOK)
@@ -94,7 +94,7 @@ func (s *tokenSuite) TestToken_Validate_TokenInHeader() {
rec := httptest.NewRecorder()

cfg := s.setupConfig()
e := NewPublicRouter(cfg, s.Storage, nil)
e := NewPublicRouter(cfg, s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusOK)
@@ -127,7 +127,7 @@ func (s *tokenSuite) TestToken_Validate_ExpiredToken() {
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()

e := NewPublicRouter(s.setupConfig(), s.Storage, nil)
e := NewPublicRouter(s.setupConfig(), s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusUnprocessableEntity)
@@ -150,7 +150,7 @@ func (s *tokenSuite) TestToken_Validate_MissingTokenFromRequest() {
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()

e := NewPublicRouter(s.setupConfig(), s.Storage, nil)
e := NewPublicRouter(s.setupConfig(), s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusBadRequest)
@@ -173,7 +173,7 @@ func (s *tokenSuite) TestToken_Validate_InvalidJson() {
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()

e := NewPublicRouter(s.setupConfig(), s.Storage, nil)
e := NewPublicRouter(s.setupConfig(), s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusBadRequest)
@@ -201,7 +201,7 @@ func (s *tokenSuite) TestToken_Validate_TokenNotFound() {
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()

e := NewPublicRouter(s.setupConfig(), s.Storage, nil)
e := NewPublicRouter(s.setupConfig(), s.Storage, nil, nil)
e.ServeHTTP(rec, req)

s.Equal(rec.Code, http.StatusNotFound)
Loading