Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
firstline144
titleclients/src/main/java/org/apache/kafka/server/authorizer/Authorizer.java
linenumberstrue
    /**
     * Check if the caller is authorized to perform the given ACL operation on at least one
     * resource of the given type.
     *
     * @param requestContext Request context including request resourceType, security protocol, and listener name
     * @param op             The ACL operation to check
     * @param resourceType   The resource type
     * @return               Return {@link AuthorizationResult#ALLOWED} if the caller is authorized to perform the
     *                       given ACL operation on at least one resource of the given type. 
     *                       Return {@link AuthorizationResult#DENIED} otherwise.
     */
    default AuthorizationResult authorizeAny(AuthorizableRequestContext requestContext, AclOperation op, ResourceType resourceType) {
        ResourcePatternFilter resourceFilter = new ResourcePatternFilter(resourceType, null, PatternType.ANY);
        AclBindingFilter aclFilter = new AclBindingFilter(
            resourceFilter, new AccessControlEntryFilter(
                requestContext.principal().toString(),
                requestContext.clientAddress().getHostAddress(),
                op,
                AclPermissionType.ANY));

        Set<String> denyPrefixes = new HashSet<>();
        Set<String> allowPrefixes = new HashSet<>();

        for (AclBinding binding : acls(aclFilter)) {
            if (binding.entry().permissionType() != AclPermissionType.ALLOW) {
                if (binding.entry().permissionType() == AclPermissionType.DENY) {
                    switch (binding.pattern().patternType()) {
                        case LITERAL:
                            if (binding.pattern().name().equals(ResourcePattern.WILDCARD_RESOURCE))
                                return AuthorizationResult.DENIED;
                            if (binding.pattern().resourceType() == ResourceType.CLUSTER &&
                                binding.pattern().name().equals(Resource.CLUSTER_NAME))
                                return AuthorizationResult.DENIED;
                            break;
                        case PREFIXED:
                            if (binding.pattern().name().isEmpty())
                                return AuthorizationResult.DENIED;
                            denyPrefixes.add(binding.pattern().name());
                            break;
                    }
                }
                continue;
            }

            switch (binding.pattern().patternType()) {
                case LITERAL:
                    if (binding.pattern().name() == ResourcePattern.WILDCARD_RESOURCE)
                        return AuthorizationResult.ALLOWED;
                    List<Action> action = Collections.singletonList(new Action(
                        op, binding.pattern(), 1, false, false));
                    if (authorize(requestContext, action).get(0) == AuthorizationResult.ALLOWED) {
                        return AuthorizationResult.ALLOWED;
                    }
                    break;
                case PREFIXED:
                    allowPrefixes.add(binding.pattern().name());
                    break;
            }
        }

        for (String allowed : allowPrefixes) {
            StringBuilder sb = new StringBuilder();
            boolean hasDominatedDeny = false;
            for (int pos = 0; pos < allowed.length(); pos++) {
                sb.append(allowed.charAt(pos));
                if (denyPrefixes.contains(sb.toString())) {
                    hasDominatedDeny = true;
                    break;
                }
            }
            if (!hasDominatedDeny)
                return AuthorizationResult.ALLOWED;
        }
        return AuthorizationResult.DENIED;
    }

...