public async Task <FrontendBehavior> ExecuteAsync(CacheItem cacheItem, string routingPayload) { if (!_coreConfiguration.Fido2.IsEnabled) { return(null); } // If this is second attempt to call same start endpoint if (cacheItem.FlowType == FlowType.Fido2Login || cacheItem.FlowType == FlowType.Fido2Register || cacheItem.FlowType == FlowType.Fido2Link || cacheItem.FlowType == FlowType.Fido2LinkWithPin || cacheItem.FlowType == FlowType.Fido2Recover || cacheItem.FlowType == FlowType.Fido2RecoverWithPin) { return(null); } // Not supported for Fido2 flows if (cacheItem.FlowType != FlowType.PartialAuthorize && cacheItem.FlowType != FlowType.Link && cacheItem.FlowType != FlowType.Recover && cacheItem.FlowType != FlowType.LinkWithPin && cacheItem.FlowType != FlowType.RecoverWithPin) { return(null); } if (string.IsNullOrEmpty(routingPayload)) { return(null); } var routing = OwnIdSerializer.Deserialize <ExtAuthenticationRouting>(routingPayload); if (routing.Authenticator != ExtAuthenticatorType.Fido2) { return(null); } if (!string.IsNullOrEmpty(routing.Error)) { _logger.LogError($"Found error in FIDO2 ExtAuthenticationRouting object: {routing.Error}"); return(null); } var initialFlowType = cacheItem.FlowType; var initialChallengeType = cacheItem.ChallengeType; switch (routing.Type) { case "l": { if (cacheItem.FlowType == FlowType.PartialAuthorize) { cacheItem.FlowType = FlowType.Fido2Login; } break; } case "r": cacheItem.FlowType = cacheItem.FlowType switch { FlowType.PartialAuthorize => FlowType.Fido2Register, FlowType.Link => FlowType.Fido2Link, FlowType.LinkWithPin => FlowType.Fido2LinkWithPin, FlowType.Recover => FlowType.Fido2Recover, FlowType.RecoverWithPin => FlowType.Fido2RecoverWithPin, _ => cacheItem.FlowType }; if (cacheItem.FlowType == FlowType.Fido2Register) { cacheItem.ChallengeType = ChallengeType.Register; } break; default: throw new InternalLogicException($"Incorrect fido2 request: '{routing.Type}'"); } if (initialFlowType == cacheItem.FlowType) { return(null); } await _cacheItemRepository.UpdateAsync(cacheItem.Context, item => { item.FlowType = cacheItem.FlowType; item.ChallengeType = cacheItem.ChallengeType; }); if (_eventsMetricsService != null && initialChallengeType != cacheItem.ChallengeType) { _eventsMetricsService?.LogSwitchAsync(initialChallengeType.ToEventType()); _eventsMetricsService?.LogStartAsync(cacheItem.ChallengeType.ToEventType()); } // TODO: rework to exclude explicit url creation return(new FrontendBehavior(StepType.Fido2Authorize, cacheItem.ChallengeType, new CallAction(_urlProvider.GetChallengeUrl(cacheItem.Context, ChallengeType.Register, "/fido2")))); }