Skip to content

Commit

Permalink
improve(passkeys): improve passkey naming
Browse files Browse the repository at this point in the history
* add cmd flag for loading aaguid-map file
* add aaguid mapper for better passkey naming
* bundle aaguid file in docker container
* refactor file loading to reuse in multiple occasions

Closes: #1027
  • Loading branch information
Stefan Jacobi committed Jan 23, 2024
1 parent 39cb070 commit abd7213
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 17 deletions.
9 changes: 7 additions & 2 deletions backend/Dockerfile
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

Expand Down Expand Up @@ -28,16 +28,21 @@ COPY build_info build_info/
COPY middleware middleware/
COPY template template/
COPY utils utils/
COPY mapper mapper/

# Load AAGUID map
RUN wget --quiet https://raw.githubusercontent.com/passkeydeveloper/passkey-authenticator-aaguids/main/aaguid.json -O aaguid.json

# 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
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/hanko .
COPY --from=builder /workspace/aaguid.json /etc/config/
USER 65532:65532

ENTRYPOINT ["/hanko"]
9 changes: 7 additions & 2 deletions backend/cmd/serve/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -15,7 +16,8 @@ import (

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

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

aaguidMap := mapper.LoadAaguidMap(&aaguidMapFile)

persister, err := persistence.New(cfg.Database)
if err != nil {
log.Fatal(err)
Expand All @@ -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, aaguidMap)
go server.StartAdmin(cfg, &wg, persister, prometheus)

wg.Wait()
},
}

cmd.Flags().StringVar(&configFile, "config", config.DefaultConfigFilePath, "config file")
cmd.Flags().StringVar(&aaguidMapFile, "aaguid-map", "", "aaguid map file")

return cmd
}
9 changes: 7 additions & 2 deletions backend/cmd/serve/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -14,7 +15,8 @@ import (

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

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

aaguidMap := mapper.LoadAaguidMap(&aaguidMapFile)

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, aaguidMap)

wg.Wait()
},
}

cmd.Flags().StringVar(&configFile, "config", config.DefaultConfigFilePath, "config file")
cmd.Flags().StringVar(&aaguidMapFile, "aaguid-map", "", "config file")

return cmd
}
19 changes: 16 additions & 3 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,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)
}
Expand Down
4 changes: 3 additions & 1 deletion backend/dto/intern/WebauthnCredential.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, aaguidMap mapper.AaguidMap) *models.WebauthnCredential {
now := time.Now().UTC()
aaguid, _ := uuid.FromBytes(credential.Authenticator.AAGUID)
credentialID := base64.RawURLEncoding.EncodeToString(credential.ID)

c := &models.WebauthnCredential{
ID: credentialID,
Name: aaguidMap.GetNameForAaguid(aaguid),
UserId: userId,
PublicKey: base64.RawURLEncoding.EncodeToString(credential.PublicKey),
AttestationType: credential.AttestationType,
Expand Down
5 changes: 3 additions & 2 deletions backend/handler/public_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, aaguidMap mapper.AaguidMap) *echo.Echo {
e := echo.New()
e.Renderer = template.NewTemplateRenderer()
e.HideBanner = true
Expand Down Expand Up @@ -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, aaguidMap)
if err != nil {
panic(fmt.Errorf("failed to create public webauthn handler: %w", err))
}
Expand Down
7 changes: 5 additions & 2 deletions backend/handler/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/dto"
"github.com/teamhanko/hanko/backend/dto/intern"
"github.com/teamhanko/hanko/backend/mapper"
"github.com/teamhanko/hanko/backend/persistence"
"github.com/teamhanko/hanko/backend/persistence/models"
"github.com/teamhanko/hanko/backend/session"
Expand All @@ -28,10 +29,11 @@ type WebauthnHandler struct {
sessionManager session.Manager
cfg *config.Config
auditLogger auditlog.Logger
aaguidMap mapper.AaguidMap
}

// NewWebauthnHandler creates a new handler which handles all webauthn related routes
func NewWebauthnHandler(cfg *config.Config, persister persistence.Persister, sessionManager session.Manager, auditLogger auditlog.Logger) (*WebauthnHandler, error) {
func NewWebauthnHandler(cfg *config.Config, persister persistence.Persister, sessionManager session.Manager, auditLogger auditlog.Logger, aaguidMap mapper.AaguidMap) (*WebauthnHandler, error) {
f := false
wa, err := webauthn.New(&webauthn.Config{
RPDisplayName: cfg.Webauthn.RelyingParty.DisplayName,
Expand Down Expand Up @@ -66,6 +68,7 @@ func NewWebauthnHandler(cfg *config.Config, persister persistence.Persister, ses
sessionManager: sessionManager,
cfg: cfg,
auditLogger: auditLogger,
aaguidMap: aaguidMap,
}, nil
}

Expand Down Expand Up @@ -196,7 +199,7 @@ func (h *WebauthnHandler) FinishRegistration(c echo.Context) error {

backupEligible := request.Response.AttestationObject.AuthData.Flags.HasBackupEligible()
backupState := request.Response.AttestationObject.AuthData.Flags.HasBackupState()
model := intern.WebauthnCredentialToModel(credential, sessionData.UserId, backupEligible, backupState)
model := intern.WebauthnCredentialToModel(credential, sessionData.UserId, backupEligible, backupState, h.aaguidMap)
err = h.persister.GetWebauthnCredentialPersisterWithConnection(tx).Create(*model)
if err != nil {
return fmt.Errorf("failed to store webauthn credential: %w", err)
Expand Down
48 changes: 48 additions & 0 deletions backend/mapper/aaguid_mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package mapper

import (
"fmt"
"github.com/gofrs/uuid"
"github.com/knadh/koanf/parsers/json"
"github.com/teamhanko/hanko/backend/config"
"log"
)

type Aaguid struct {
Name string `json:"name"`
IconLight string `json:"icon_light"`
IconDark string `json:"icon_dark"`
}

type AaguidMap map[string]Aaguid

func (w AaguidMap) GetNameForAaguid(aaguid uuid.UUID) *string {
if webauthnAaguid, ok := w[aaguid.String()]; ok {
return &webauthnAaguid.Name
} else {
return nil
}
}

func LoadAaguidMap(aaguidFilePath *string) AaguidMap {
k, err := config.LoadFile(aaguidFilePath, json.Parser())

if err != nil {
log.Println(err)
return nil
}

if k == nil {
log.Println("no aaguid map file provided. Skipping...")
return nil
}

var aaguidMap AaguidMap
err = k.Unmarshal("", &aaguidMap)
if err != nil {
log.Println(fmt.Errorf("unable to unmarshal aaguid map: %w", err))
return nil
}

return aaguidMap
}
5 changes: 3 additions & 2 deletions backend/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"github.com/labstack/echo/v4"
"github.com/teamhanko/hanko/backend/config"
"github.com/teamhanko/hanko/backend/handler"
"github.com/teamhanko/hanko/backend/mapper"
"github.com/teamhanko/hanko/backend/persistence"
"sync"
)

func StartPublic(cfg *config.Config, wg *sync.WaitGroup, persister persistence.Persister, prometheus echo.MiddlewareFunc) {
func StartPublic(cfg *config.Config, wg *sync.WaitGroup, persister persistence.Persister, prometheus echo.MiddlewareFunc, aaguidMap mapper.AaguidMap) {
defer wg.Done()
router := handler.NewPublicRouter(cfg, persister, prometheus)
router := handler.NewPublicRouter(cfg, persister, prometheus, aaguidMap)
router.Logger.Fatal(router.Start(cfg.Server.Public.Address))
}

Expand Down
Loading

0 comments on commit abd7213

Please sign in to comment.