feat: cred props

feat-otp-verification
James Elliott 2023-02-18 15:36:58 +11:00
parent 5be5de02d8
commit e5cdb175b4
No known key found for this signature in database
GPG Key ID: 0F1C4A096E857E49
4 changed files with 48 additions and 41 deletions

View File

@ -87,18 +87,20 @@ func WebauthnRegistrationPUT(ctx *middlewares.AutheliaCtx) {
} }
var ( var (
opts *protocol.CredentialCreation creation *protocol.CredentialCreation
) )
opts := []webauthn.RegistrationOption{
webauthn.WithExclusions(user.WebAuthnCredentialDescriptors()),
webauthn.WithExtensions(map[string]any{"credProps": true}),
webauthn.WithResidentKeyRequirement(protocol.ResidentKeyRequirementDiscouraged),
}
data := session.Webauthn{ data := session.Webauthn{
DisplayName: bodyJSON.Description, Description: bodyJSON.Description,
} }
extensions := map[string]any{ if creation, data.SessionData, err = w.BeginRegistration(user, opts...); err != nil {
"credProps": true,
}
if opts, data.SessionData, err = w.BeginRegistration(user, webauthn.WithExclusions(user.WebAuthnCredentialDescriptors()), webauthn.WithExtensions(extensions)); err != nil {
ctx.Logger.Errorf("Unable to create %s registration challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) ctx.Logger.Errorf("Unable to create %s registration challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err)
respondUnauthorized(ctx, messageUnableToRegisterSecurityKey) respondUnauthorized(ctx, messageUnableToRegisterSecurityKey)
@ -116,7 +118,7 @@ func WebauthnRegistrationPUT(ctx *middlewares.AutheliaCtx) {
return return
} }
if err = ctx.SetJSONBody(opts); err != nil { if err = ctx.SetJSONBody(creation); err != nil {
ctx.Logger.Errorf(logFmtErrWriteResponseBody, regulation.AuthTypeWebauthn, userSession.Username, err) ctx.Logger.Errorf(logFmtErrWriteResponseBody, regulation.AuthTypeWebauthn, userSession.Username, err)
respondUnauthorized(ctx, messageUnableToRegisterSecurityKey) respondUnauthorized(ctx, messageUnableToRegisterSecurityKey)
@ -197,34 +199,9 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) {
return return
} }
var discoverable bool device := model.NewWebauthnDeviceFromCredential(w.Config.RPID, userSession.Username, userSession.Webauthn.Description, credential)
if value, ok := response.ClientExtensionResults["credProps"]; ok { device.Discoverable = webauthnCredentialCreationIsDiscoverable(ctx, response)
switch credprops := value.(type) {
case map[string]any:
ctx.Logger.Debug("Is type")
var v any
if v, ok = credprops["rk"]; ok {
ctx.Logger.Debug("found rk")
if discoverable, ok = v.(bool); ok {
ctx.Logger.Debug("found rk bool")
} else {
ctx.Logger.Debugf("not found rk bool %T", v)
}
} else {
ctx.Logger.Debug("not found rk")
}
default:
ctx.Logger.Debugf("type is %T", credprops)
}
}
device := model.NewWebauthnDeviceFromCredential(w.Config.RPID, userSession.Username, userSession.Webauthn.DisplayName, credential)
device.Discoverable = discoverable
if err = ctx.Providers.StorageProvider.SaveWebauthnDevice(ctx, device); err != nil { if err = ctx.Providers.StorageProvider.SaveWebauthnDevice(ctx, device); err != nil {
ctx.Logger.Errorf("Unable to save %s device registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) ctx.Logger.Errorf("Unable to save %s device registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err)

View File

@ -45,20 +45,19 @@ func WebauthnAssertionGET(ctx *middlewares.AutheliaCtx) {
return return
} }
var opts = []webauthn.LoginOption{
webauthn.WithAllowedCredentials(user.WebAuthnCredentialDescriptors()),
}
extensions := map[string]any{} extensions := map[string]any{}
if user.HasFIDOU2F() { if user.HasFIDOU2F() {
extensions["appid"] = w.Config.RPOrigins[0] extensions["appid"] = w.Config.RPOrigins[0]
} }
var opts = []webauthn.LoginOption{
webauthn.WithAllowedCredentials(user.WebAuthnCredentialDescriptors()),
}
if len(extensions) != 0 { if len(extensions) != 0 {
opts = append(opts, webauthn.WithAssertionExtensions(extensions)) opts = append(opts, webauthn.WithAssertionExtensions(extensions))
} }
var assertion *protocol.CredentialAssertion var assertion *protocol.CredentialAssertion
data := session.Webauthn{} data := session.Webauthn{}

View File

@ -70,3 +70,34 @@ func newWebauthn(ctx *middlewares.AutheliaCtx) (w *webauthn.WebAuthn, err error)
return webauthn.New(config) return webauthn.New(config)
} }
func webauthnCredentialCreationIsDiscoverable(ctx *middlewares.AutheliaCtx, response *protocol.ParsedCredentialCreationData) (discoverable bool) {
if value, ok := response.ClientExtensionResults["credProps"]; ok {
switch credentialProperties := value.(type) {
case map[string]any:
var v any
if v, ok = credentialProperties["rk"]; ok {
if discoverable, ok = v.(bool); ok {
ctx.Logger.WithFields(map[string]any{"discoverable": discoverable}).Trace("Determined Credential Discoverability via Client Extension Results")
return discoverable
} else {
ctx.Logger.WithFields(map[string]any{"discoverable": false}).Trace("Assuming Credential Discoverability is false as the 'rk' field for the 'credProps' extension in the Client Extension Results was not a boolean")
}
} else {
ctx.Logger.WithFields(map[string]any{"discoverable": false}).Trace("Assuming Credential Discoverability is false as the 'rk' field for the 'credProps' extension was missing from the Client Extension Results")
}
return false
default:
ctx.Logger.WithFields(map[string]any{"discoverable": false}).Trace("Assuming Credential Discoverability is false as the 'credProps' extension in the Client Extension Results does not appear to be a dictionary")
return false
}
}
ctx.Logger.WithFields(map[string]any{"discoverable": false}).Trace("Assuming Credential Discoverability is false as the 'credProps' extension is missing from the Client Extension Results")
return false
}

View File

@ -48,7 +48,7 @@ type UserSession struct {
// Webauthn holds the standard webauthn session data plus some extra. // Webauthn holds the standard webauthn session data plus some extra.
type Webauthn struct { type Webauthn struct {
*webauthn.SessionData *webauthn.SessionData
DisplayName string Description string
} }
// Identity of the user who is being verified. // Identity of the user who is being verified.