/* * Copyright 2010 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 com.amazonaws.auth.policy.internal; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.amazonaws.auth.policy.Action; import com.amazonaws.auth.policy.Condition; import com.amazonaws.auth.policy.Policy; import com.amazonaws.auth.policy.Principal; import com.amazonaws.auth.policy.Resource; import com.amazonaws.auth.policy.Statement; import com.amazonaws.util.json.JSONException; import com.amazonaws.util.json.JSONWriter; /** * Serializes an AWS policy object to a JSON string, suitable for sending to an * AWS service. */ public class JsonPolicyWriter { /** * Converts the specified AWS policy object to a JSON string, suitable for * passing to an AWS service. * * @param policy * The AWS policy object to convert to a JSON string. * * @return The JSON string representation of the specified policy object. * * @throws IllegalArgumentException * If the specified policy is null or invalid and cannot be * serialized to a JSON string. */ public String writePolicyToString(Policy policy) { if (policy == null) { throw new IllegalArgumentException("Policy cannot be null"); } StringWriter writer = new StringWriter(); try { JSONWriter generator = new JSONWriter(writer); writePolicy(policy, generator); return writer.toString(); } catch (Exception e) { String message = "Unable to serialize policy to JSON string: " + e.getMessage(); throw new IllegalArgumentException(message, e); } finally { try {writer.close();} catch (Exception e) {} } } private void writePolicy(Policy policy, JSONWriter generator) throws JSONException, IOException { generator.object(); generator.key("Version").value(policy.getVersion()); if (policy.getId() != null) { generator.key("Id").value(policy.getId()); } generator.key("Statement").array(); for (Statement statement : policy.getStatements()) { generator.object(); if (statement.getId() != null) { generator.key("Sid").value(statement.getId()); } generator.key("Effect").value(statement.getEffect().toString()); writePrincipals(statement, generator); writeActions(statement, generator); writeResources(statement, generator); writeConditions(statement, generator); generator.endObject(); } generator.endArray(); generator.endObject(); } private void writeConditions(Statement statement, JSONWriter generator) throws IOException, JSONException { List<Condition> conditions = statement.getConditions(); if (conditions == null || conditions.isEmpty()) return; /* * We could have multiple conditions that are the same condition type * but use different condition keys. In JSON and XML, those conditions * must be siblings, otherwise data can be lost when they get parsed. */ Map<String, List<Condition>> conditionsByType = sortConditionsByType(conditions); generator.key("Condition").object(); for (String conditionType : conditionsByType.keySet()) { generator.key(conditionType).object(); /* * We could also have multiple conditions that use the same type and * same key, in which case, we need to push them together as one entry * when we send the JSON representation. */ Map<String, List<String>> conditionValuesByKey = sortConditionsByKey(conditionsByType.get(conditionType)); for (String conditionKey : conditionValuesByKey.keySet()) { generator.key(conditionKey).array(); for (String value : conditionValuesByKey.get(conditionKey)) { generator.value(value); } generator.endArray(); } generator.endObject(); } generator.endObject(); } private Map<String, List<String>> sortConditionsByKey(List<Condition> conditions) { Map<String, List<String>> conditionValuesByConditionKey = new HashMap<String, List<String>>(); for (Condition condition : conditions) { String key = condition.getConditionKey(); List<String> values = condition.getValues(); if (conditionValuesByConditionKey.containsKey(key) == false) { conditionValuesByConditionKey.put(key, new ArrayList<String>()); } conditionValuesByConditionKey.get(key).addAll(values); } return conditionValuesByConditionKey; } private Map<String, List<Condition>> sortConditionsByType(List<Condition> conditions) { Map<String, List<Condition>> conditionsByType = new HashMap<String, List<Condition>>(); for (Condition condition : conditions) { String conditionType = condition.getType(); if (conditionsByType.get(conditionType) == null) { conditionsByType.put(conditionType, new ArrayList<Condition>()); } conditionsByType.get(conditionType).add(condition); } return conditionsByType; } private void writeResources(Statement statement, JSONWriter generator) throws IOException, JSONException { List<Resource> resources = statement.getResources(); if (resources == null || resources.isEmpty()) return; generator.key("Resource").array(); for (Resource resource : resources) { generator.value(resource.getId()); } generator.endArray(); } private void writeActions(Statement statement, JSONWriter generator) throws IOException, JSONException { List<Action> actions = statement.getActions(); if (actions == null || actions.isEmpty()) return; generator.key("Action").array(); for (Action action : actions) { generator.value(action.getActionName()); } generator.endArray(); } /** * Uses the specified generator to write the JSON data for the principals in * the specified policy statement. */ private void writePrincipals(Statement statement, JSONWriter generator) throws IOException, JSONException { List<Principal> principals = statement.getPrincipals(); if (principals == null || principals.isEmpty()) return; generator.key("Principal").object(); Map<String, List<String>> principalIdsByScheme = new HashMap<String, List<String>>(); for (Principal p : principals) { List<String> principalIds = principalIdsByScheme.get(p.getProvider()); if (principalIds == null) { principalIds = new ArrayList<String>(); principalIdsByScheme.put(p.getProvider(), principalIds); } principalIds.add(p.getId()); } for (String scheme : principalIdsByScheme.keySet()) { generator.key(scheme).array(); for (String principalId : principalIdsByScheme.get(scheme)) { generator.value(principalId); } generator.endArray(); } generator.endObject(); } }