Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extend AWS policy #187

Merged
merged 9 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sns/IPrincipalValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.Sns;

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

public interface IPrincipalValue
{
void Serialize(IAsyncApiWriter writer);
}

public struct PrincipalObject : IPrincipalValue
{
private KeyValuePair<string, StringOrStringList> PrincipalValue;

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

public 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();
}
}

public struct PrincipalStar : IPrincipalValue
{
private string PrincipalValue;

public PrincipalStar(string principalValue)
{
this.PrincipalValue = principalValue;
}

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

writer.WriteValue(this.PrincipalValue);
}
}
69 changes: 69 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sns/Principal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) The LEGO Group. All rights reserved.

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;

public class Principal : IAsyncApiElement
{
public Principal(IPrincipalValue value)
{
this.Value = value;
}

public IPrincipalValue Value { get; set; }

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 Principal(new PrincipalStar(nodeValue));

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.");
}

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

return new Principal(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);
}
}
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.Value.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
54 changes: 54 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sqs/IPrincipalValue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.Sqs;

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

public interface IPrincipalValue
{
void Serialize(IAsyncApiWriter writer);
}

public struct PrincipalObject : IPrincipalValue
{
private KeyValuePair<string, StringOrStringList> PrincipalValue;

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

public 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();
}
}

struct PrincipalStar : IPrincipalValue
VisualBean marked this conversation as resolved.
Show resolved Hide resolved
{
private string PrincipalValue;

public PrincipalStar(string principalValue)
{
this.PrincipalValue = principalValue;
}

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

writer.WriteValue(this.PrincipalValue);
}
}
69 changes: 69 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/Sqs/Principal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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;

public class Principal : IAsyncApiElement
{
public Principal(IPrincipalValue value)
{
this.Value = value;
}

public IPrincipalValue Value { get; set; }
Gadam8 marked this conversation as resolved.
Show resolved Hide resolved

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 Principal(new PrincipalStar(nodeValue));

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.");
}

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

return new Principal(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);
}
}
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
Loading
Loading