feat: cred props
parent
5be5de02d8
commit
e5cdb175b4
|
@ -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)
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue