public async Task ExecuteAsync(UserIdentitiesData input, CacheItem relatedItem)
        {
            var recoveryToken = !string.IsNullOrEmpty(input.RecoveryData) ? Guid.NewGuid().ToString("N") : null;

            // Credentials created at web app
            if (input.ActualChallengeType.HasValue && input.ActualChallengeType != relatedItem.ChallengeType)
            {
                relatedItem.ChallengeType = input.ActualChallengeType.Value;
            }
            // check if users exists or not. If not - then this is LinkOnLogin
            else if (relatedItem.ChallengeType == ChallengeType.Login)
            {
                var isUserExists = await _userHandlerAdapter.IsUserExistsAsync(input.PublicKey);

                if (!isUserExists)
                {
                    relatedItem.ChallengeType = ChallengeType.LinkOnLogin;
                }
            }

            await _cacheItemRepository.UpdateAsync(relatedItem.Context, item =>
            {
                item.ChallengeType = relatedItem.ChallengeType;
                item.RecoveryToken = recoveryToken;
                item.RecoveryData  = input.RecoveryData;
                item.FinishFlow(input.DID, input.PublicKey);
            });
        }
Exemple #2
0
        public async Task <bool> ExecuteAsync(UserIdentification input)
        {
            // Do nothing for recovery flow
            // var relatedItem = await _cacheItemService.GetCacheItemByContextAsync(input.Context);
            // if (relatedItem.ChallengeType == ChallengeType.Recover)
            //     return false;

            bool result;

            if (string.IsNullOrWhiteSpace(input.UserIdentifier))
            {
                result = false;
            }
            else if (!input.AuthenticatorType.HasValue)
            {
                result = await _userHandlerAdapter.IsUserExistsAsync(input.UserIdentifier);
            }
            else
            {
                result = input.AuthenticatorType switch
                {
                    ExtAuthenticatorType.Fido2 =>
                    await _userHandlerAdapter.IsFido2UserExistsAsync(input.UserIdentifier),
                    _ => false
                }
            };

            return(result);
        }
Exemple #3
0
        public async Task <AuthResult> ExecuteAsync(AddConnectionRequest request)
        {
            var cacheItem = await _cacheItemRepository.GetAsync(request.Context);

            if (cacheItem.Nonce != request.Nonce || cacheItem.Status != CacheItemStatus.Popped)
            {
                throw new CommandValidationException(
                          $"No cacheItem with context {request.Context} and nonce {request.Nonce}");
            }

            if (cacheItem.FlowType != FlowType.Fido2Register && cacheItem.FlowType != FlowType.PartialAuthorize)
            {
                throw new CommandValidationException($"Wrong flow type {cacheItem.FlowType}");
            }

            var connectionState = await _accountLinkHandler.GetCurrentUserLinkStateAsync(request.Payload);

            if (connectionState.ConnectedDevicesCount >= _coreConfiguration.MaximumNumberOfConnectedDevices)
            {
                return(new AuthResult(_localizationService.GetLocalizedString("Error_PhoneAlreadyConnected")));
            }

            var connectionExists = !string.IsNullOrEmpty(cacheItem.Fido2CredentialId)
                ? await _userHandlerAdapter.IsFido2UserExistsAsync(cacheItem.Fido2CredentialId)
                : await _userHandlerAdapter.IsUserExistsAsync(cacheItem.PublicKey);

            if (connectionExists)
            {
                return(new AuthResult("Can not add connection. Connection already exists"));
            }

            await _accountLinkHandler.OnLinkAsync(connectionState.DID, new OwnIdConnection
            {
                Fido2CredentialId     = cacheItem.Fido2CredentialId,
                Fido2SignatureCounter = cacheItem.Fido2SignatureCounter.ToString(),
                PublicKey             = cacheItem.PublicKey,
                RecoveryToken         = cacheItem.RecoveryToken,
                RecoveryData          = cacheItem.RecoveryData,
                AuthType = cacheItem.AuthCookieType switch
                {
                    CookieType.Fido2 => ConnectionAuthType.Fido2,
                    CookieType.Passcode => ConnectionAuthType.Passcode,
                    _ => ConnectionAuthType.Basic
                }
            });
        public async Task <CacheItem> ExecuteAsync(JwtContainer input, CacheItem relatedItem)
        {
            var userData = _jwtService.GetDataFromJwt <UserIdentitiesData>(input.Jwt).Data;

            if (relatedItem.ChallengeType == ChallengeType.Link && relatedItem.DID != userData.DID)
            {
                throw new CommandValidationException($"Wrong user for linking {userData.DID}");
            }


            var userExists = await _userHandlerAdapter.IsUserExistsAsync(userData.PublicKey);

            if (userExists)
            {
                throw new OwnIdException(ErrorType.UserAlreadyExists);
            }

            // preventing data substitution
            userData.DID = relatedItem.DID;

            // TODO: code duplication
            var recoveryToken = !string.IsNullOrEmpty(userData.RecoveryData) ? Guid.NewGuid().ToString("N") : null;

            var connection = new OwnIdConnection
            {
                PublicKey     = userData.PublicKey,
                RecoveryToken = recoveryToken,
                RecoveryData  = userData.RecoveryData,
                AuthType      = relatedItem.AuthCookieType switch
                {
                    CookieType.Fido2 => ConnectionAuthType.Fido2,
                    CookieType.Passcode => ConnectionAuthType.Passcode,
                    _ => ConnectionAuthType.Basic
                }
            };

            await _linkHandler.OnLinkAsync(userData.DID, connection);

            return(await _cacheItemRepository.UpdateAsync(relatedItem.Context, item =>
            {
                item.RecoveryToken = recoveryToken;
                item.RecoveryData = userData.RecoveryData;
                item.FinishFlow(userData.DID, userData.PublicKey);
            }));
        }
        private async Task <GetStatusResponse> GetContextStatus(GetStatusRequest requestItem)
        {
            if (string.IsNullOrEmpty(requestItem.Context) || string.IsNullOrEmpty(requestItem.Nonce))
            {
                return(null);
            }

            var cacheItem = await _cacheItemRepository.GetAsync(requestItem.Context, false);

            if (cacheItem == null || cacheItem.Nonce != requestItem.Nonce || cacheItem.Status == CacheItemStatus.Popped)
            {
                return(null);
            }

            var result = new GetStatusResponse
            {
                Status  = cacheItem.Status,
                Context = requestItem.Context
            };

            if (cacheItem.SecurityCode != null && cacheItem.Status == CacheItemStatus.WaitingForApproval)
            {
                // TODO: refactor to entity
                result.Payload = new
                {
                    data = new
                    {
                        pin = cacheItem.SecurityCode
                    }
                }
            }
            ;

            if (cacheItem.Status != CacheItemStatus.Finished)
            {
                return(result);
            }

            await _cacheItemRepository.UpdateAsync(cacheItem.Context,
                                                   item => { item.Status = CacheItemStatus.Popped; });

            if (!string.IsNullOrEmpty(cacheItem.Error))
            {
                result.Payload = new AuthResult <object>(_localizationService.GetLocalizedString(cacheItem.Error));
                return(result);
            }

            var action = cacheItem.ChallengeType.ToString();

            if (cacheItem.FlowType == FlowType.Authorize)
            {
                result.Payload = await _userHandlerAdapter.OnSuccessLoginAsync(cacheItem.DID, cacheItem.PublicKey);
            }
            else
            {
                switch (cacheItem.ChallengeType)
                {
                case ChallengeType.Login
                    when cacheItem.FlowType == FlowType.Fido2Login &&
                    string.IsNullOrWhiteSpace(cacheItem.Fido2CredentialId):
                {
                    var errorMessage = _localizationService.GetLocalizedString("Error_UserNotFound");
                    result.Payload = new AuthResult <object>(errorMessage);
                    break;
                }

                case ChallengeType.Login
                    when !string.IsNullOrWhiteSpace(cacheItem.Fido2CredentialId) &&
                    cacheItem.Fido2SignatureCounter.HasValue:
                {
                    result.Payload = await _userHandlerAdapter.OnSuccessLoginByFido2Async(
                        cacheItem.Fido2CredentialId,
                        cacheItem.Fido2SignatureCounter.Value);

                    break;
                }

                case ChallengeType.Login:
                    result.Payload = await _userHandlerAdapter.OnSuccessLoginByPublicKeyAsync(cacheItem.PublicKey);

                    break;

                case ChallengeType.LinkOnLogin:
                    action         = ChallengeType.Link.ToString();
                    result.Payload = SetPartialRegisterResult(cacheItem);
                    break;

                case ChallengeType.Register
                    when await _userHandlerAdapter.IsUserExistsAsync(cacheItem.PublicKey):
                {
                    var errorMessage = _localizationService.GetLocalizedString("Error_PhoneAlreadyConnected");
                    result.Payload = new AuthResult <object>(errorMessage);
                    return(result);
                }

                case ChallengeType.Register
                    when string.IsNullOrWhiteSpace(cacheItem.Fido2CredentialId):
                {
                    result.Payload = SetPartialRegisterResult(cacheItem);
                    break;
                }

                case ChallengeType.Register:
                    result.Payload = new
                    {
                        data = new
                        {
                            pubKey = cacheItem.PublicKey,
                            fido2SignatureCounter = cacheItem.Fido2SignatureCounter.ToString(),
                            fido2CredentialId     = cacheItem.Fido2CredentialId
                        }
                    };
                    if (cacheItem.InitialChallengeType == ChallengeType.Login &&
                        cacheItem.ChallengeType == ChallengeType.Register)
                    {
                        action = ChallengeType.Link.ToString();
                    }
                    break;

                //
                // TODO: fix needed at web-ui-sdk to avoid error in console if data is undefined
                //
                case ChallengeType.Recover:
                case ChallengeType.Link:
                    result.Payload = new
                    {
                        data = new { }
                    };
                    break;
                }
            }

            result.Metadata = _jwtService.GenerateDataJwt(new Dictionary <string, object>
            {
                {
                    "data", new
                    {
                        action,
                        authType = cacheItem.GetAuthType()
                    }
                }
            });

            return(result);
        }