Пример #1
0
        public async void CanThrottle()
        {
            Assert.True(LimitRequestZone.TryParse("zone=mylimit rate=10r/s burst=20", out var limitRequestZone));
            var delay   = new MockDelay();
            var service = new RateLimitService(delay);
            await Assert.ThrowsAsync <KeyNotFoundException>(async() => await service.Throttle("mylimit"));

            Assert.Equal(0, service.BucketsCount);

            service.SetZone(limitRequestZone);

            var throttling = service.Throttle("mylimit"); // Will execute immediately, slot reserved until +100

            Assert.True(throttling.Wait(10));
            Assert.Equal(1, service.BucketsCount);

            var throttling2 = service.Throttle("mylimit"); // Will execute at +100, slot reserved until +200

            Assert.False(throttling2.Wait(10));
            Assert.Equal(1, service.BucketsCount);
            delay.AdvanceMilliseconds(100);
            Assert.True(throttling2.Wait(10));
            Assert.True(throttling2.IsCompletedSuccessfully);
            Assert.Equal(1, service.BucketsCount); // Still bucket 1, because the slot used by throttling2 is still here

            delay.AdvanceMilliseconds(100);        // The bucket should be empty, though but wait one more period before deleting the bucket
            Thread.Sleep(10);
            Assert.Equal(1, service.BucketsCount);

            delay.AdvanceMilliseconds(100);
            Thread.Sleep(100);
            Assert.Equal(0, service.BucketsCount);
        }
Пример #2
0
        internal async Task Handle(HttpContext ctx)
        {
            if (ctx.Request.Path.Value == "")
            {
                if (!(await TryExtractArguments(ctx.Request, ctx.RequestAborted) is string[] args))
                {
                    ctx.Response.StatusCode = 400;
                    return;
                }
                var response = await Transport.SendCommandAsync(args, ctx.RequestAborted);

                ctx.Response.StatusCode = 200;
                ctx.Response.Headers["Content-Type"] = "text/plain";
                await ctx.Response.WriteAsync(response, ctx.RequestAborted);

                return;
            }
            else if (ctx.Request.Path.StartsWithSegments("/request-permission"))
            {
                if (!ctx.Request.Headers.TryGetValue("Origin", out var origin))
                {
                    ctx.Response.StatusCode = 400;
                    return;
                }

                if (!await _rateLimitService.Throttle(RateLimitZones.Prompt, ThrottleSingletonObject, ctx.RequestAborted))
                {
                    ctx.Response.StatusCode = 429;
                    return;
                }
                if (await _permissionsService.IsGranted(origin))
                {
                    ctx.Response.StatusCode = 200;
                    return;
                }
                if (!await _permissionPrompt.AskPermission(origin, ctx.RequestAborted))
                {
                    _logger.LogInformation($"Permission to {origin} got denied");
                    ctx.Response.StatusCode = 401;
                    return;
                }
                _logger.LogInformation($"Permission to {origin} got granted");
                ctx.Response.StatusCode = 200;
                return;
            }
        }
Пример #3
0
        public async Task <IActionResult> CreateUser(CreateApplicationUserRequest request, CancellationToken cancellationToken = default)
        {
            if (request.Email is null)
            {
                ModelState.AddModelError(nameof(request.Email), "Email is missing");
            }
            if (!string.IsNullOrEmpty(request.Email) && !Validation.EmailValidator.IsEmail(request.Email))
            {
                ModelState.AddModelError(nameof(request.Email), "Invalid email");
            }
            if (request.Password is null)
            {
                ModelState.AddModelError(nameof(request.Password), "Password is missing");
            }
            if (!ModelState.IsValid)
            {
                return(this.CreateValidationError(ModelState));
            }
            if (User.Identity is null)
            {
                throw new JsonHttpException(this.StatusCode(401));
            }
            var anyAdmin = (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
            var policies = await _settingsRepository.GetSettingAsync <PoliciesSettings>() ?? new PoliciesSettings();

            var isAuth = User.Identity.AuthenticationType == GreenfieldConstants.AuthenticationType;

            // If registration are locked and that an admin exists, don't accept unauthenticated connection
            if (anyAdmin && policies.LockSubscription && !isAuth)
            {
                return(this.CreateAPIError(401, "unauthenticated", "New user creation isn't authorized to users who are not admin"));
            }

            // Even if subscription are unlocked, it is forbidden to create admin unauthenticated
            if (anyAdmin && request.IsAdministrator is true && !isAuth)
            {
                return(this.CreateAPIError(401, "unauthenticated", "New admin creation isn't authorized to users who are not admin"));
            }
            // You are de-facto admin if there is no other admin, else you need to be auth and pass policy requirements
            bool isAdmin = anyAdmin ? (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded &&
                           (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.Unrestricted))).Succeeded &&
                           isAuth
                                    : true;

            // You need to be admin to create an admin
            if (request.IsAdministrator is true && !isAdmin)
            {
                return(this.CreateAPIPermissionError(Policies.Unrestricted, $"Insufficient API Permissions. Please use an API key with permission: {Policies.Unrestricted} and be an admin."));
            }

            if (!isAdmin && (policies.LockSubscription || (await _settingsRepository.GetPolicies()).DisableNonAdminCreateUserApi))
            {
                // If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
                var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
                if (!isAuth || !canCreateUser)
                {
                    return(this.CreateAPIPermissionError(Policies.CanCreateUser));
                }
            }

            var user = new ApplicationUser
            {
                UserName = request.Email,
                Email    = request.Email,
                RequiresEmailConfirmation = policies.RequiresConfirmedEmail,
                Created = DateTimeOffset.UtcNow,
            };
            var passwordValidation = await this._passwordValidator.ValidateAsync(_userManager, user, request.Password);

            if (!passwordValidation.Succeeded)
            {
                foreach (var error in passwordValidation.Errors)
                {
                    ModelState.AddModelError(nameof(request.Password), error.Description);
                }
                return(this.CreateValidationError(ModelState));
            }
            if (!isAdmin)
            {
                if (!await _throttleService.Throttle(ZoneLimits.Register, this.HttpContext.Connection.RemoteIpAddress, cancellationToken))
                {
                    return(new TooManyRequestsResult(ZoneLimits.Register));
                }
            }
            var identityResult = await _userManager.CreateAsync(user, request.Password);

            if (!identityResult.Succeeded)
            {
                foreach (var error in identityResult.Errors)
                {
                    if (error.Code == "DuplicateUserName")
                    {
                        ModelState.AddModelError(nameof(request.Email), error.Description);
                    }
                    else
                    {
                        ModelState.AddModelError(string.Empty, error.Description);
                    }
                }
                return(this.CreateValidationError(ModelState));
            }

            if (request.IsAdministrator is true)
            {
                if (!anyAdmin)
                {
                    await _roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
                }
                await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);

                if (!anyAdmin)
                {
                    var settings = await _settingsRepository.GetSettingAsync <ThemeSettings>();

                    if (settings != null)
                    {
                        settings.FirstRun = false;
                        await _settingsRepository.UpdateSetting(settings);
                    }

                    await _settingsRepository.FirstAdminRegistered(policies, _options.UpdateUrl != null, _options.DisableRegistration, Logs);
                }
            }
            _eventAggregator.Publish(new UserRegisteredEvent()
            {
                RequestUri = Request.GetAbsoluteRootUri(), User = user, Admin = request.IsAdministrator is true
            });
Пример #4
0
        public async Task <ActionResult <ApplicationUserData> > CreateUser(CreateApplicationUserRequest request, CancellationToken cancellationToken = default)
        {
            if (request?.Email is null)
            {
                return(BadRequest(CreateValidationProblem(nameof(request.Email), "Email is missing")));
            }
            if (!Validation.EmailValidator.IsEmail(request.Email))
            {
                return(BadRequest(CreateValidationProblem(nameof(request.Email), "Invalid email")));
            }
            if (request?.Password is null)
            {
                return(BadRequest(CreateValidationProblem(nameof(request.Password), "Password is missing")));
            }
            var anyAdmin = (await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin)).Any();
            var policies = await _settingsRepository.GetSettingAsync <PoliciesSettings>() ?? new PoliciesSettings();

            var isAuth = User.Identity.AuthenticationType == APIKeyConstants.AuthenticationType;

            // If registration are locked and that an admin exists, don't accept unauthenticated connection
            if (anyAdmin && policies.LockSubscription && !isAuth)
            {
                return(Unauthorized());
            }

            // Even if subscription are unlocked, it is forbidden to create admin unauthenticated
            if (anyAdmin && request.IsAdministrator is true && !isAuth)
            {
                return(Forbid(AuthenticationSchemes.ApiKey));
            }
            // You are de-facto admin if there is no other admin, else you need to be auth and pass policy requirements
            bool isAdmin = anyAdmin ? (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanModifyServerSettings))).Succeeded &&
                           (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.Unrestricted))).Succeeded &&
                           isAuth
                                    : true;

            // You need to be admin to create an admin
            if (request.IsAdministrator is true && !isAdmin)
            {
                return(Forbid(AuthenticationSchemes.ApiKey));
            }

            if (!isAdmin && policies.LockSubscription)
            {
                // If we are not admin and subscriptions are locked, we need to check the Policies.CanCreateUser.Key permission
                var canCreateUser = (await _authorizationService.AuthorizeAsync(User, null, new PolicyRequirement(Policies.CanCreateUser))).Succeeded;
                if (!isAuth || !canCreateUser)
                {
                    return(Forbid(AuthenticationSchemes.ApiKey));
                }
            }

            var user = new ApplicationUser
            {
                UserName = request.Email,
                Email    = request.Email,
                RequiresEmailConfirmation = policies.RequiresConfirmedEmail
            };
            var passwordValidation = await this._passwordValidator.ValidateAsync(_userManager, user, request.Password);

            if (!passwordValidation.Succeeded)
            {
                foreach (var error in passwordValidation.Errors)
                {
                    ModelState.AddModelError(nameof(request.Password), error.Description);
                }
                return(BadRequest(new ValidationProblemDetails(ModelState)));
            }
            if (!isAdmin)
            {
                if (!await _throttleService.Throttle(ZoneLimits.Register, this.HttpContext.Connection.RemoteIpAddress, cancellationToken))
                {
                    return(new TooManyRequestsResult(ZoneLimits.Register));
                }
            }
            var identityResult = await _userManager.CreateAsync(user, request.Password);

            if (!identityResult.Succeeded)
            {
                foreach (var error in identityResult.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
                return(BadRequest(new ValidationProblemDetails(ModelState)));
            }

            if (request.IsAdministrator is true)
            {
                if (!anyAdmin)
                {
                    await _roleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin));
                }
                await _userManager.AddToRoleAsync(user, Roles.ServerAdmin);

                if (!anyAdmin)
                {
                    if (_options.DisableRegistration)
                    {
                        // automatically lock subscriptions now that we have our first admin
                        Logs.PayServer.LogInformation("First admin created, disabling subscription (disable-registration is set to true)");
                        policies.LockSubscription = true;
                        await _settingsRepository.UpdateSetting(policies);
                    }
                }
            }
            _eventAggregator.Publish(new UserRegisteredEvent()
            {
                Request = Request, User = user, Admin = request.IsAdministrator is true
            });