private void AddMethod(Effect effect, HttpVerb verb, string resource)
        {
            if (verb == null)
            {
                throw new AuthPolicyBuilderException($"{nameof(verb)} cannot be null");
            }
            if (resource == null)
            {
                throw new AuthPolicyBuilderException($"{nameof(resource)} cannot be null");
            }
            if (!_pathRegex.IsMatch(resource))
            {
                throw new AuthPolicyBuilderException($"{nameof(resource)} is invalid: {resource}. Path should match {_pathRegex}");
            }

            var cleanedResource = resource.First() == '/' ? resource.Substring(1) : resource;

            var arn = new ApiGatewayArn
            {
                Verb     = verb.ToString(),
                Resource = cleanedResource,
            };

            switch (effect)
            {
            case Effect.Deny:
                _denyMethodArns.Add(arn);
                return;

            case Effect.Allow:
                _allowMethodArns.Add(arn);
                return;
            }
        }
        public static ApiGatewayArn Parse(string value)
        {
            try
            {
                var result = new ApiGatewayArn();

                string[] arnSplit = value.Split(':');
                result.Partition    = arnSplit[1];
                result.Service      = arnSplit[2];
                result.Region       = arnSplit[3];
                result.AwsAccountId = arnSplit[4];

                string[] pathSplit = arnSplit[5].Split('/');
                result.RestApiId = pathSplit[0];
                result.Stage     = pathSplit[1];
                result.Verb      = pathSplit[2];

                if (pathSplit.Length > 3)
                {
                    result.Resource = string.Join("/", pathSplit.Skip(3));
                }

                return(result);
            }
            catch (Exception)
            {
                throw new ApiGatewayArnException($"Invalid method arn: '{value}'");
            }
        }
 public static bool TryParse(string value, out ApiGatewayArn methodArn)
 {
     try
     {
         methodArn = Parse(value);
         return(true);
     }
     catch
     {
         methodArn = null;
         return(false);
     }
 }
        public void ValidateRequest(Request request, out ApiGatewayArn apiGatewayArn)
        {
            _logger.LogTrace("Validating request");

            apiGatewayArn = null;
            var validationMessages = new List <string>();

            if (request == null)
            {
                validationMessages.Add("Request is required.");
            }
            else
            {
                if (request.Type == null)
                {
                    validationMessages.Add("Expected 'type' to have been provided.");
                }
                else if (request.Type.ToUpperInvariant() != "TOKEN")
                {
                    validationMessages.Add("Expected 'type' to have value 'TOKEN'.");
                }

                if (string.IsNullOrWhiteSpace(request.AuthorizationToken))
                {
                    validationMessages.Add("Expected 'authorizationToken' to have been provided.");
                }
                else if (!new Regex("^Bearer .*$").IsMatch(request.AuthorizationToken))
                {
                    validationMessages.Add("Expected 'authorizationToken' to match '^Bearer .*$'.");
                }

                if (string.IsNullOrWhiteSpace(request.MethodArn))
                {
                    validationMessages.Add("Expected 'methodArn' to have been provided.");
                }
                else if (!ApiGatewayArn.TryParse(request.MethodArn, out apiGatewayArn))
                {
                    validationMessages.Add($"Could not parse 'methodArn': '{request.MethodArn}'.");
                }
            }

            if (validationMessages.Count > 0)
            {
                _logger.LogError("Request validation failed", new { validationMessages });
                throw new RequestValidationException();
            }

            _logger.LogTrace("Successfully validated request");
        }
        public Response Build(ApiGatewayArn apiGatewayArn, string principalId = null)
        {
            PopulateMethods(apiGatewayArn);
            var statements = GetStatements();

            return(new Response
            {
                PrincipalID = principalId,
                PolicyDocument = new APIGatewayCustomAuthorizerPolicy
                {
                    Version = _policyVersion,
                    Statement = statements,
                }
            });
        }
示例#6
0
        public Response Authorize(Request request)
        {
            ApiGatewayArn apiGatewayArn = null;
            string        principalId   = null;

            try
            {
                _logger.LogDebug("Authorizing");

                _requestValidationService.ValidateRequest(request, out apiGatewayArn);

                TokenValidationParameters jwtConfig = _tokenConfigService.GetJwtConfig();

                string          token = request.AuthorizationToken?.Replace("Bearer ", "");
                ClaimsPrincipal user  = _tokenValidationService.ValidateToken(token, jwtConfig);

                principalId = _claimsPrincipalService.GetPrincipalId(user);

                // this uses the all-or-nothing auth strategy by default:
                _policyBuilder.AllowAllMethods();

                // however, you could allow/deny specific methods/resources based off the user's claims, for example:
                // Claim role = user.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role);
                // HttpVerb verb = role?.Value == "admin" ? HttpVerb.All : HttpVerb.Get;
                // _policyBuilder.AllowMethod(verb, "config");

                _logger.LogDebug("Authorization succeeded", new { principalId });
            }
            catch (BaseException ex)
            {
                _logger.LogDebug(ex.Message, new { ex.InnerException });
                _logger.LogDebug("Authorization failed", new { });

                // you may choose to throw an unauthorized exception here instead of returning a "deny all" policy
                // throw new UnauthorizedException();

                _policyBuilder.DenyAllMethods();
            }

            Response response = _policyBuilder.Build(apiGatewayArn, principalId);

            // you can add key-value pairs that can be accessed in API Gateway via $context.authorizer.<key>
            // response.Context.Add("key", "value");

            return(response);
        }
        private void PopulateMethods(ApiGatewayArn apiGatewayArn)
        {
            populate(_allowMethodArns);
            populate(_denyMethodArns);

            void populate(List <ApiGatewayArn> methodArns)
            {
                foreach (var arn in methodArns)
                {
                    arn.Partition    = apiGatewayArn.Partition;
                    arn.Service      = apiGatewayArn.Service.DefaultTo("*");
                    arn.Region       = apiGatewayArn.Region.DefaultTo("*");
                    arn.AwsAccountId = apiGatewayArn.AwsAccountId;
                    arn.RestApiId    = apiGatewayArn.RestApiId.DefaultTo("*");
                    arn.Stage        = apiGatewayArn.Stage.DefaultTo("*");
                }
            }
        }