Skip to content

Commit

Permalink
feat: extend AWS policy (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadam8 authored Aug 15, 2024
1 parent 129622a commit 9cc759f
Show file tree
Hide file tree
Showing 14 changed files with 395 additions and 55 deletions.
63 changes: 63 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sns/Principal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace LEGO.AsyncAPI.Bindings.Sns;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

public abstract class Principal : IAsyncApiElement
{
public abstract void Serialize(IAsyncApiWriter writer);

public static Principal Parse(ParseNode node)
{
switch (node)
{
case ValueNode:
var nodeValue = node.GetScalarValue();
if (!IsStarString(nodeValue))
{
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Principal value without a property name can only be a string value of '*'.");
}

return new PrincipalStar();

case MapNode mapNode:
{
var propertyNode = mapNode.First();
if (!IsValidPrincipalProperty(propertyNode.Name))
{
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Node should contain a valid AWS principal property name.");
}

var principalValue = new KeyValuePair<string, StringOrStringList>(
propertyNode.Name,
StringOrStringList.Parse(propertyNode.Value));

return new PrincipalObject(principalValue);
}

default:
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Node should contain a string value of '*' or a valid AWS principal property.");
}
}

private static bool IsStarString(JsonNode value)
{
var element = JsonDocument.Parse(value.ToJsonString()).RootElement;

return element.ValueKind == JsonValueKind.String && element.ValueEquals("*");
}

private static bool IsValidPrincipalProperty(string property)
{
return new[] { "AWS", "Service" }.Contains(property);
}
}
27 changes: 27 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sns/PrincipalObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace LEGO.AsyncAPI.Bindings.Sns;

using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Writers;

public class PrincipalObject : Principal
{
private KeyValuePair<string, StringOrStringList> PrincipalValue;

public PrincipalObject(KeyValuePair<string, StringOrStringList> principalValue)
{
this.PrincipalValue = principalValue;
}

public override void Serialize(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();
writer.WriteRequiredObject(this.PrincipalValue.Key, this.PrincipalValue.Value, (w, t) => t.Value.Write(w));
writer.WriteEndObject();
}
}
24 changes: 24 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sns/PrincipalStar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace LEGO.AsyncAPI.Bindings.Sns;

using System;
using LEGO.AsyncAPI.Writers;

public class PrincipalStar : Principal
{
private string PrincipalValue;

public PrincipalStar()
{
this.PrincipalValue = "*";
}

public override void Serialize(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteValue(this.PrincipalValue);
}
}
4 changes: 3 additions & 1 deletion src/LEGO.AsyncAPI.Bindings/Sns/SnsChannelBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ public class SnsChannelBinding : ChannelBinding<SnsChannelBinding>
private static FixedFieldMap<Statement> statementFixedFields = new()
{
{ "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName<Effect>(); } },
{ "principal", (a, n) => { a.Principal = StringOrStringList.Parse(n); } },
{ "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
{ "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
{ "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
{ "condition", (a, n) => { a.Condition = n.CreateAny(); } },
};

/// <inheritdoc/>
Expand Down
26 changes: 20 additions & 6 deletions src/LEGO.AsyncAPI.Bindings/Sns/Statement.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.Sns
{
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Attributes;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

public class Statement : IAsyncApiExtensible
{
/// <summary>
/// Indicates whether the policy allows or denies access.
/// </summary>
public Effect Effect { get; set; }

/// <summary>
/// The AWS account or resource ARN that this statement applies to.
/// The AWS account(s) or resource ARN(s) that this statement applies to.
/// </summary>
// public StringOrStringList Principal { get; set; }
public StringOrStringList Principal { get; set; }
public Principal Principal { get; set; }

/// <summary>
/// The SNS permission being allowed or denied e.g. sns:Publish
/// The SNS permission being allowed or denied e.g. sns:Publish.
/// </summary>
public StringOrStringList Action { get; set; }

/// <summary>
/// The resource(s) that this policy applies to.
/// </summary>
public StringOrStringList? Resource { get; set; }

/// <summary>
/// Specific circumstances under which the policy grants permission.
/// </summary>
public AsyncApiAny? Condition { get; set; }

public IDictionary<string, IAsyncApiExtension> Extensions { get; set; } = new Dictionary<string, IAsyncApiExtension>();

public void Serialize(IAsyncApiWriter writer)
Expand All @@ -34,8 +46,10 @@ public void Serialize(IAsyncApiWriter writer)

writer.WriteStartObject();
writer.WriteRequiredProperty("effect", this.Effect.GetDisplayName());
writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Value.Write(w));
writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w));
writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w));
writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w));
writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Write(w));
writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
Expand Down
65 changes: 65 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sqs/Principal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.Sqs;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

public abstract class Principal : IAsyncApiElement
{
public abstract void Serialize(IAsyncApiWriter writer);

public static Principal Parse(ParseNode node)
{
switch (node)
{
case ValueNode:
var nodeValue = node.GetScalarValue();
if (!IsStarString(nodeValue))
{
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Principal value without a property name can only be a string value of '*'.");
}

return new PrincipalStar();

case MapNode mapNode:
{
var propertyNode = mapNode.First();
if (!IsValidPrincipalProperty(propertyNode.Name))
{
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Node should contain a valid AWS principal property name.");
}

var principalValue = new KeyValuePair<string, StringOrStringList>(
propertyNode.Name,
StringOrStringList.Parse(propertyNode.Value));

return new PrincipalObject(principalValue);
}

default:
throw new ArgumentException($"An error occured while parsing a {nameof(Principal)} node. " +
$"Node should contain a string value of '*' or a valid AWS principal property.");
}
}

private static bool IsStarString(JsonNode value)
{
var element = JsonDocument.Parse(value.ToJsonString()).RootElement;

return element.ValueKind == JsonValueKind.String && element.ValueEquals("*");
}

private static bool IsValidPrincipalProperty(string property)
{
return new[] { "AWS", "Service" }.Contains(property);
}
}
27 changes: 27 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace LEGO.AsyncAPI.Bindings.Sqs;

using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Writers;

public class PrincipalObject : Principal
{
private KeyValuePair<string, StringOrStringList> PrincipalValue;

public PrincipalObject(KeyValuePair<string, StringOrStringList> principalValue)
{
this.PrincipalValue = principalValue;
}

public override void Serialize(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();
writer.WriteRequiredObject(this.PrincipalValue.Key, this.PrincipalValue.Value, (w, t) => t.Value.Write(w));
writer.WriteEndObject();
}
}
24 changes: 24 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sqs/PrincipalStar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace LEGO.AsyncAPI.Bindings.Sqs;

using System;
using LEGO.AsyncAPI.Writers;

public class PrincipalStar : Principal
{
private string PrincipalValue;

public PrincipalStar()
{
this.PrincipalValue = "*";
}

public override void Serialize(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteValue(this.PrincipalValue);
}
}
4 changes: 3 additions & 1 deletion src/LEGO.AsyncAPI.Bindings/Sqs/SqsChannelBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ public class SqsChannelBinding : ChannelBinding<SqsChannelBinding>
private static FixedFieldMap<Statement> statementFixedFields = new()
{
{ "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName<Effect>(); } },
{ "principal", (a, n) => { a.Principal = StringOrStringList.Parse(n); } },
{ "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
{ "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
{ "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
{ "condition", (a, n) => { a.Condition = n.CreateAny(); } },
};

public override void SerializeProperties(IAsyncApiWriter writer)
Expand Down
4 changes: 3 additions & 1 deletion src/LEGO.AsyncAPI.Bindings/Sqs/SqsOperationBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ public class SqsOperationBinding : OperationBinding<SqsOperationBinding>
private static FixedFieldMap<Statement> statementFixedFields = new()
{
{ "effect", (a, n) => { a.Effect = n.GetScalarValue().GetEnumFromDisplayName<Effect>(); } },
{ "principal", (a, n) => { a.Principal = StringOrStringList.Parse(n); } },
{ "principal", (a, n) => { a.Principal = Principal.Parse(n); } },
{ "action", (a, n) => { a.Action = StringOrStringList.Parse(n); } },
{ "resource", (a, n) => { a.Resource = StringOrStringList.Parse(n); } },
{ "condition", (a, n) => { a.Condition = n.CreateAny(); } },
};

public override void SerializeProperties(IAsyncApiWriter writer)
Expand Down
25 changes: 20 additions & 5 deletions src/LEGO.AsyncAPI.Bindings/Sqs/Statement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,37 @@ namespace LEGO.AsyncAPI.Bindings.Sqs
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Attributes;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

public class Statement : IAsyncApiExtensible
{
/// <summary>
/// Indicates whether the policy allows or denies access.
/// </summary>
public Effect Effect { get; set; }

/// <summary>
/// The AWS account or resource ARN that this statement applies to.
/// The AWS account(s) or resource ARN(s) that this statement applies to.
/// </summary>
// public StringOrStringList Principal { get; set; }
public StringOrStringList Principal { get; set; }
public Principal Principal { get; set; }

/// <summary>
/// The SNS permission being allowed or denied e.g. sns:Publish
/// The SNS permission being allowed or denied e.g. sns:Publish.
/// </summary>
public StringOrStringList Action { get; set; }

/// <summary>
/// The resource(s) that this policy applies to.
/// </summary>
public StringOrStringList? Resource { get; set; }

/// <summary>
/// Specific circumstances under which the policy grants permission.
/// </summary>
public AsyncApiAny? Condition { get; set; }

public IDictionary<string, IAsyncApiExtension> Extensions { get; set; } = new Dictionary<string, IAsyncApiExtension>();

public void Serialize(IAsyncApiWriter writer)
Expand All @@ -34,8 +47,10 @@ public void Serialize(IAsyncApiWriter writer)

writer.WriteStartObject();
writer.WriteRequiredProperty("effect", this.Effect.GetDisplayName());
writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Value.Write(w));
writer.WriteRequiredObject("principal", this.Principal, (w, t) => t.Serialize(w));
writer.WriteRequiredObject("action", this.Action, (w, t) => t.Value.Write(w));
writer.WriteOptionalObject("resource", this.Resource, (w, t) => t?.Value.Write(w));
writer.WriteOptionalObject("condition", this.Condition, (w, t) => t?.Write(w));
writer.WriteExtensions(this.Extensions);
writer.WriteEndObject();
}
Expand Down
Loading

0 comments on commit 9cc759f

Please sign in to comment.