/* * Copyright 2010-2013 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. */ using System; using System.IO; using System.Collections.Generic; using System.Text; using ThirdParty.Json.LitJson; using System.Globalization; namespace Amazon.Auth.AccessControlPolicy.Internal { /// /// Serializes an AWS policy object to a JSON string, suitable for sending to an /// AWS service. /// internal static 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 static string WritePolicyToString(bool prettyPrint, Policy policy) { if (policy == null) { throw new ArgumentNullException("policy"); } StringWriter writer = new StringWriter(CultureInfo.InvariantCulture); try { JsonWriter generator = new JsonWriter(writer); generator.IndentValue = 4; generator.PrettyPrint = prettyPrint; writePolicy(policy, generator); return writer.ToString().Trim(); } catch (Exception e) { string message = "Unable to serialize policy to JSON string: " + e.Message; throw new ArgumentException(message, e); } } private static void writePolicy(Policy policy, JsonWriter generator) { generator.WriteObjectStart(); writePropertyValue(generator, JsonDocumentFields.VERSION, policy.Version); if (policy.Id != null) { writePropertyValue(generator, JsonDocumentFields.POLICY_ID, policy.Id); } generator.WritePropertyName(JsonDocumentFields.STATEMENT); generator.WriteArrayStart(); foreach (Statement statement in policy.Statements) { generator.WriteObjectStart(); if (statement.Id != null) { writePropertyValue(generator, JsonDocumentFields.STATEMENT_ID, statement.Id); } writePropertyValue(generator, JsonDocumentFields.STATEMENT_EFFECT, statement.Effect.ToString()); writePrincipals(statement, generator); writeActions(statement, generator); writeResources(statement, generator); writeConditions(statement, generator); generator.WriteObjectEnd(); } generator.WriteArrayEnd(); generator.WriteObjectEnd(); } /// /// Uses the specified generator to write the JSON data for the principals in /// the specified policy statement. /// private static void writePrincipals(Statement statement, JsonWriter generator) { IList principals = statement.Principals; if (principals == null || principals.Count == 0) return; generator.WritePropertyName(JsonDocumentFields.PRINCIPAL); if (principals.Count == 1 && principals[0] != null && principals[0].Provider.Equals(Principal.ANONYMOUS_PROVIDER, StringComparison.Ordinal)) { generator.Write("*"); return; } generator.WriteObjectStart(); Dictionary> principalIdsByScheme = new Dictionary>(); foreach (Principal p in principals) { List principalIds; if (!principalIdsByScheme.TryGetValue(p.Provider, out principalIds)) { principalIds = new List(); principalIdsByScheme[p.Provider] = principalIds; } principalIds.Add(p.Id); } foreach (string scheme in principalIdsByScheme.Keys) { generator.WritePropertyName(scheme); if (principalIdsByScheme[scheme].Count > 1) { generator.WriteArrayStart(); } foreach (string principalId in principalIdsByScheme[scheme]) { generator.Write(principalId); } if (principalIdsByScheme[scheme].Count > 1) { generator.WriteArrayEnd(); } } generator.WriteObjectEnd(); } private static void writeActions(Statement statement, JsonWriter generator) { IList actions = statement.Actions; if (actions == null || actions.Count == 0) { return; } generator.WritePropertyName(JsonDocumentFields.ACTION); if (actions.Count > 1) { generator.WriteArrayStart(); } foreach (ActionIdentifier action in actions) { generator.Write(action.ActionName); } if (actions.Count > 1) { generator.WriteArrayEnd(); } } private static void writeResources(Statement statement, JsonWriter generator) { IList resources = statement.Resources; if (resources == null || resources.Count == 0) { return; } generator.WritePropertyName(JsonDocumentFields.RESOURCE); if (resources.Count > 1) { generator.WriteArrayStart(); } foreach (Resource resource in resources) { generator.Write(resource.Id); } if (resources.Count > 1) { generator.WriteArrayEnd(); } } private static void writeConditions(Statement statement, JsonWriter generator) { IList conditions = statement.Conditions; if (conditions == null || conditions.Count == 0) { return; } /* * The condition values must be grouped by all the unique condition types and keys because * the values are written out as an array per type and key. */ Dictionary>> conditionsByTypeAndKeys = sortConditionsByTypeAndKey(conditions); generator.WritePropertyName(JsonDocumentFields.CONDITION); generator.WriteObjectStart(); foreach (KeyValuePair>> typeEntry in conditionsByTypeAndKeys) { generator.WritePropertyName(typeEntry.Key); generator.WriteObjectStart(); foreach (KeyValuePair> keyEntry in typeEntry.Value) { IList conditionValues = keyEntry.Value; if (conditionValues.Count == 0) continue; generator.WritePropertyName(keyEntry.Key); if (conditionValues.Count > 1) { generator.WriteArrayStart(); } if (conditionValues != null && conditionValues.Count != 0) { foreach (string conditionValue in conditionValues) { generator.Write(conditionValue); } } if (conditionValues.Count > 1) { generator.WriteArrayEnd(); } } generator.WriteObjectEnd(); } generator.WriteObjectEnd(); } /// /// This sorts the conditions by condition type and key with the list of values for that combination. /// /// The list of conditions to be sorted. /// private static Dictionary>> sortConditionsByTypeAndKey(IList conditions) { Dictionary>> conditionsByTypeAndKeys = new Dictionary>>(); foreach (Condition condition in conditions) { string conditionType = condition.Type; string conditionKey = condition.ConditionKey; Dictionary> keys; if (!conditionsByTypeAndKeys.TryGetValue(conditionType, out keys)) { keys = new Dictionary>(); conditionsByTypeAndKeys[conditionType] = keys; } List values; if (!keys.TryGetValue(conditionKey, out values)) { values = new List(); keys[conditionKey] = values; } if (condition.Values != null) { foreach (string value in condition.Values) { values.Add(value); } } } return conditionsByTypeAndKeys; } private static void writePropertyValue(JsonWriter generator, string propertyName, string value) { generator.WritePropertyName(propertyName); generator.Write(value); } } }