All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.awssdk.policybuilder.iam.internal.DefaultIamPolicyReader Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package software.amazon.awssdk.policybuilder.iam.internal;

import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.policybuilder.iam.IamCondition;
import software.amazon.awssdk.policybuilder.iam.IamPolicy;
import software.amazon.awssdk.policybuilder.iam.IamPolicyReader;
import software.amazon.awssdk.policybuilder.iam.IamPrincipal;
import software.amazon.awssdk.policybuilder.iam.IamStatement;
import software.amazon.awssdk.protocols.jsoncore.JsonNode;
import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser;
import software.amazon.awssdk.utils.Validate;

/**
 * Default implementation of {@link IamPolicyReader}.
 *
 * @see IamPolicyReader#create
 */
@SdkInternalApi
public final class DefaultIamPolicyReader implements IamPolicyReader {
    private static final JsonNodeParser JSON_NODE_PARSER = JsonNodeParser.create();

    @Override
    public IamPolicy read(String policy) {
        return read(policy.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public IamPolicy read(byte[] policy) {
        return read(new ByteArrayInputStream(policy));
    }

    @Override
    public IamPolicy read(InputStream policy) {
        return readPolicy(JSON_NODE_PARSER.parse(policy));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        return 0;
    }

    private IamPolicy readPolicy(JsonNode policyNode) {
        Map policyObject = expectObject(policyNode, "Policy did not start with {");

        return IamPolicy.builder()
                        .version(getString(policyObject, "Version"))
                        .id(getString(policyObject, "Id"))
                        .statements(readStatements(policyObject.get("Statement")))
                        .build();
    }

    private List readStatements(JsonNode statementsNode) {
        if (statementsNode == null) {
            return null;
        }

        if (statementsNode.isArray()) {
            return statementsNode.asArray()
                                 .stream()
                                 .map(n -> expectObject(n, "Statement entry"))
                                 .map(this::readStatement)
                                 .collect(toList());
        }

        if (statementsNode.isObject()) {
            return singletonList(readStatement(statementsNode.asObject()));
        }

        throw new IllegalArgumentException("Statement was not an array or object.");
    }

    private IamStatement readStatement(Map statementObject) {
        return IamStatement.builder()
                           .sid(getString(statementObject, "Sid"))
                           .effect(getString(statementObject, "Effect"))
                           .principals(readPrincipals(statementObject, "Principal"))
                           .notPrincipals(readPrincipals(statementObject, "NotPrincipal"))
                           .actionIds(readStringOrArrayAsList(statementObject, "Action"))
                           .notActionIds(readStringOrArrayAsList(statementObject, "NotAction"))
                           .resourceIds(readStringOrArrayAsList(statementObject, "Resource"))
                           .notResourceIds(readStringOrArrayAsList(statementObject, "NotResource"))
                           .conditions(readConditions(statementObject.get("Condition")))
                           .build();
    }

    private List readPrincipals(Map statementObject, String name) {
        JsonNode principalsNode = statementObject.get(name);

        if (principalsNode == null) {
            return null;
        }

        if (principalsNode.isString() && principalsNode.asString().equals(IamPrincipal.ALL.id())) {
            return singletonList(IamPrincipal.ALL);
        }

        if (principalsNode.isObject()) {
            List result = new ArrayList<>();
            Map principalsNodeObject = principalsNode.asObject();
            principalsNodeObject.keySet().forEach(
                k -> result.addAll(IamPrincipal.createAll(k, readStringOrArrayAsList(principalsNodeObject, k)))
            );
            return result;
        }

        throw new IllegalArgumentException(name + " was not \"" + IamPrincipal.ALL.id() + "\" or an object");
    }

    private List readConditions(JsonNode conditionNode) {
        if (conditionNode == null) {
            return null;
        }

        Map conditionObject = expectObject(conditionNode, "Condition");

        List result = new ArrayList<>();

        conditionObject.forEach((operator, keyValueNode) -> {
            Map keyValueObject = expectObject(keyValueNode, "Condition key");
            keyValueObject.forEach((key, value) -> {
                if (value.isString()) {
                    result.add(IamCondition.create(operator, key, value.asString()));
                } else if (value.isArray()) {
                    List values =
                        value.asArray()
                             .stream()
                             .map(valueNode -> expectString(valueNode, "Condition values entry"))
                             .collect(toList());
                    result.addAll(IamCondition.createAll(operator, key, values));
                }
            });

        });

        return result;
    }

    private List readStringOrArrayAsList(Map statementObject, String nodeKey) {
        JsonNode node = statementObject.get(nodeKey);

        if (node == null) {
            return null;
        }

        if (node.isString()) {
            return singletonList(node.asString());
        }

        if (node.isArray()) {
            return node.asArray()
                       .stream()
                       .map(n -> expectString(n, nodeKey + " entry"))
                       .collect(toList());
        }

        throw new IllegalArgumentException(nodeKey + " was not an array or string");
    }

    private String getString(Map object, String key) {
        JsonNode node = object.get(key);
        if (node == null) {
            return null;
        }

        return expectString(node, key);
    }

    private String expectString(JsonNode node, String name) {
        Validate.isTrue(node.isString(), "%s was not a string", name);
        return node.asString();
    }

    private Map expectObject(JsonNode node, String name) {
        Validate.isTrue(node.isObject(), "%s was not an object", name);
        return node.asObject();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy