Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Cratis.Arc.Authorization;

namespace Cratis.Arc.ProxyGenerator.ControllerBased.for_MethodInfoExtensions;

/// <summary>
/// Holds the shapes roles can be declared in, for reading them back.
/// </summary>
/// <remarks>
/// Both <c>Cratis.Arc.Authorization</c> and <c>Microsoft.AspNetCore.Authorization</c> declare an
/// <c>Authorize</c> attribute, so the ASP.NET Core one is written out in full where the named-argument form is needed.
/// </remarks>
public class RoleSecuredTypes
{
[Roles("Librarian")]
public void SingleRoleFromConstructor() { }

[Roles("Librarian", "Admin")]
public void MultipleRolesFromConstructor() { }

[Microsoft.AspNetCore.Authorization.Authorize(Roles = "Librarian")]
public void RoleFromNamedArgument() { }

[Roles("Librarian")]
[Microsoft.AspNetCore.Authorization.Authorize(Roles = "Librarian")]
public void RoleFromBothForms() { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;

namespace Cratis.Arc.ProxyGenerator.ControllerBased.for_MethodInfoExtensions.when_extracting_roles;

public class from_both_forms_combined : Specification
{
MethodInfo _method;
IEnumerable<string> _result;

void Establish() => _method = typeof(RoleSecuredTypes).GetMethod(nameof(RoleSecuredTypes.RoleFromBothForms));

void Because() => _result = _method.GetRoles();

[Fact] void should_deduplicate_the_roles() => _result.ShouldContainOnly(["Librarian"]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;

namespace Cratis.Arc.ProxyGenerator.ControllerBased.for_MethodInfoExtensions.when_extracting_roles;

public class from_constructor_form_with_multiple_roles : Specification
{
MethodInfo _method;
IEnumerable<string> _result;

void Establish() => _method = typeof(RoleSecuredTypes).GetMethod(nameof(RoleSecuredTypes.MultipleRolesFromConstructor));

void Because() => _result = _method.GetRoles();

[Fact] void should_yield_all_roles() => _result.ShouldContainOnly(["Librarian", "Admin"]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;

namespace Cratis.Arc.ProxyGenerator.ControllerBased.for_MethodInfoExtensions.when_extracting_roles;

public class from_constructor_form_with_single_role : Specification
{
MethodInfo _method;
IEnumerable<string> _result;

void Establish() => _method = typeof(RoleSecuredTypes).GetMethod(nameof(RoleSecuredTypes.SingleRoleFromConstructor));

void Because() => _result = _method.GetRoles();

[Fact] void should_yield_the_role() => _result.ShouldContainOnly(["Librarian"]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;

namespace Cratis.Arc.ProxyGenerator.ControllerBased.for_MethodInfoExtensions.when_extracting_roles;

public class from_named_argument_form : Specification
{
MethodInfo _method;
IEnumerable<string> _result;

void Establish() => _method = typeof(RoleSecuredTypes).GetMethod(nameof(RoleSecuredTypes.RoleFromNamedArgument));

void Because() => _result = _method.GetRoles();

[Fact] void should_yield_the_role() => _result.ShouldContainOnly(["Librarian"]);
}
11 changes: 11 additions & 0 deletions Source/DotNET/Tools/ProxyGenerator/MethodInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static IEnumerable<string> GetRolesFromAttributesData(IEnumerable<CustomAttribut
continue;
}

// Named-argument form, e.g. [Authorize(Roles = "Librarian")].
var rolesArg = attr.NamedArguments.FirstOrDefault(a => a.MemberName == "Roles");
if (rolesArg != default && rolesArg.TypedValue.Value is string rolesStr && !string.IsNullOrEmpty(rolesStr))
{
Expand All @@ -113,6 +114,16 @@ static IEnumerable<string> GetRolesFromAttributesData(IEnumerable<CustomAttribut
yield return role;
}
}

// Constructor form, e.g. [Roles("Librarian", "Admin")] where the attribute takes a params string[].
if (attr.ConstructorArguments.Count > 0 &&
attr.ConstructorArguments[0].Value is IReadOnlyCollection<CustomAttributeTypedArgument> roleArgs)
{
foreach (var role in roleArgs.Select(a => a.Value as string).Where(r => !string.IsNullOrEmpty(r)))
{
yield return role!;
}
}
}
}

Expand Down
Loading