merge(identity): integrate identity contracts baseline
This commit is contained in:
commit
3bb0ce47ef
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,8 @@
|
|||||||
.tasks/
|
.tasks/
|
||||||
.agile/
|
.agile/
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
TestResults/
|
||||||
|
.vs/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
|||||||
8
BuildingBlock.Identity.slnx
Normal file
8
BuildingBlock.Identity.slnx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<Solution>
|
||||||
|
<Folder Name="/src/">
|
||||||
|
<Project Path="src/BuildingBlock.Identity.Contracts/BuildingBlock.Identity.Contracts.csproj" />
|
||||||
|
</Folder>
|
||||||
|
<Folder Name="/tests/">
|
||||||
|
<Project Path="tests/BuildingBlock.Identity.Contracts.UnitTests/BuildingBlock.Identity.Contracts.UnitTests.csproj" />
|
||||||
|
</Folder>
|
||||||
|
</Solution>
|
||||||
@ -8,6 +8,7 @@
|
|||||||
| thalos-service policy contracts | Contracts/Policies | Preserve policy semantics and required fields |
|
| thalos-service policy contracts | Contracts/Policies | Preserve policy semantics and required fields |
|
||||||
| thalos-service policy context contracts | Contracts/Context | Keep field naming stable for compatibility window |
|
| thalos-service policy context contracts | Contracts/Context | Keep field naming stable for compatibility window |
|
||||||
| thalos-bff refresh session contracts | Contracts/Sessions | Candidate for shared capability standardization |
|
| thalos-bff refresh session contracts | Contracts/Sessions | Candidate for shared capability standardization |
|
||||||
|
| provider flow metadata (JWT/Azure/Google) | Contracts/Conventions | Provider metadata stays transport-neutral and additive |
|
||||||
|
|
||||||
## Namespace Strategy
|
## Namespace Strategy
|
||||||
- Current Thalos namespaces are mapped to `BuildingBlock.Identity.Contracts.*`.
|
- Current Thalos namespaces are mapped to `BuildingBlock.Identity.Contracts.*`.
|
||||||
@ -18,3 +19,4 @@
|
|||||||
2. Add compatibility bridge in Thalos consumers.
|
2. Add compatibility bridge in Thalos consumers.
|
||||||
3. Migrate service consumers first, then BFF consumers.
|
3. Migrate service consumers first, then BFF consumers.
|
||||||
4. Deprecate old namespace usage after compatibility window.
|
4. Deprecate old namespace usage after compatibility window.
|
||||||
|
5. Keep provider enum and provider-specific fields additive to avoid breaking consumers.
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marker contract for identity capability request/response definitions.
|
||||||
|
/// </summary>
|
||||||
|
public interface IIdentityCapabilityContract
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Grpc;
|
||||||
|
using BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Adapters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines gRPC mapping boundary for identity capability requests.
|
||||||
|
/// </summary>
|
||||||
|
public interface IIdentityGrpcContractAdapter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Maps request into gRPC contract shape.
|
||||||
|
/// </summary>
|
||||||
|
IdentityPolicyGrpcContract ToGrpc(EvaluateIdentityPolicyRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps gRPC contract shape into request.
|
||||||
|
/// </summary>
|
||||||
|
EvaluateIdentityPolicyRequest FromGrpc(IdentityPolicyGrpcContract contract);
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\blueprint-platform\src\Core.Blueprint.Common\Core.Blueprint.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines shared envelope metadata for identity capability requests.
|
||||||
|
/// </summary>
|
||||||
|
public interface IIdentityContractRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets request envelope metadata.
|
||||||
|
/// </summary>
|
||||||
|
IdentityContractEnvelope Envelope { get; }
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supported identity authentication providers.
|
||||||
|
/// </summary>
|
||||||
|
public enum IdentityAuthProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// AgileWebs-issued internal JWT flow.
|
||||||
|
/// </summary>
|
||||||
|
InternalJwt = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Microsoft Entra ID / Azure AD OAuth/OIDC flow.
|
||||||
|
/// </summary>
|
||||||
|
AzureAd = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Google OAuth/OIDC flow.
|
||||||
|
/// </summary>
|
||||||
|
Google = 2
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines transport-neutral envelope metadata for identity contract messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ContractVersion">Contract schema version.</param>
|
||||||
|
/// <param name="CorrelationId">Correlation identifier for cross-service tracing.</param>
|
||||||
|
public sealed record IdentityContractEnvelope(string ContractVersion, string CorrelationId);
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marker type for identity capability package discovery.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class IdentityPackageContract
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
namespace BuildingBlock.Identity.Contracts.Grpc;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines transport-neutral shape for policy evaluation gRPC contract mapping.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="PermissionCode">Permission code.</param>
|
||||||
|
/// <param name="Provider">Auth provider.</param>
|
||||||
|
public sealed record IdentityPolicyGrpcContract(
|
||||||
|
string SubjectId,
|
||||||
|
string TenantId,
|
||||||
|
string PermissionCode,
|
||||||
|
string Provider = "InternalJwt");
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests identity policy evaluation for a subject and permission.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="PermissionCode">Permission code to evaluate.</param>
|
||||||
|
/// <param name="Provider">Auth provider used for the request.</param>
|
||||||
|
public sealed record EvaluateIdentityPolicyRequest(
|
||||||
|
string SubjectId,
|
||||||
|
string TenantId,
|
||||||
|
string PermissionCode,
|
||||||
|
IdentityAuthProvider Provider = IdentityAuthProvider.InternalJwt)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests identity provider token exchange for a subject token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="Provider">External identity provider.</param>
|
||||||
|
/// <param name="ExternalToken">Provider-issued token (id/access token).</param>
|
||||||
|
/// <param name="CorrelationId">Correlation identifier.</param>
|
||||||
|
public sealed record ExchangeIdentityProviderTokenRequest(
|
||||||
|
string TenantId,
|
||||||
|
IdentityAuthProvider Provider,
|
||||||
|
string ExternalToken,
|
||||||
|
string CorrelationId = "") : IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests identity policy context lookup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="PermissionCode">Permission code to evaluate.</param>
|
||||||
|
/// <param name="Provider">Auth provider used for the request.</param>
|
||||||
|
public sealed record IdentityPolicyContextRequest(
|
||||||
|
string SubjectId,
|
||||||
|
string TenantId,
|
||||||
|
string PermissionCode,
|
||||||
|
IdentityAuthProvider Provider = IdentityAuthProvider.InternalJwt)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests identity token issuance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="Provider">Auth provider used for the request.</param>
|
||||||
|
/// <param name="ExternalToken">External provider token when applicable.</param>
|
||||||
|
public sealed record IssueIdentityTokenRequest(
|
||||||
|
string SubjectId,
|
||||||
|
string TenantId,
|
||||||
|
IdentityAuthProvider Provider = IdentityAuthProvider.InternalJwt,
|
||||||
|
string ExternalToken = "") : IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests identity session refresh.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="RefreshToken">Refresh token value.</param>
|
||||||
|
/// <param name="CorrelationId">Correlation identifier.</param>
|
||||||
|
/// <param name="Provider">Auth provider used for the request.</param>
|
||||||
|
public sealed record RefreshIdentitySessionRequest(
|
||||||
|
string RefreshToken,
|
||||||
|
string CorrelationId,
|
||||||
|
IdentityAuthProvider Provider = IdentityAuthProvider.InternalJwt)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns identity policy evaluation result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="PermissionCode">Permission code evaluated.</param>
|
||||||
|
/// <param name="IsAllowed">Whether access is granted.</param>
|
||||||
|
public sealed record EvaluateIdentityPolicyResponse(string SubjectId, string PermissionCode, bool IsAllowed)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns token exchange result from an external provider token.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Resolved identity subject identifier.</param>
|
||||||
|
/// <param name="TenantId">Tenant identifier.</param>
|
||||||
|
/// <param name="Provider">External identity provider.</param>
|
||||||
|
/// <param name="IsAuthenticated">Whether provider token was accepted.</param>
|
||||||
|
public sealed record ExchangeIdentityProviderTokenResponse(
|
||||||
|
string SubjectId,
|
||||||
|
string TenantId,
|
||||||
|
IdentityAuthProvider Provider,
|
||||||
|
bool IsAuthenticated) : IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns policy context lookup result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SubjectId">Identity subject identifier.</param>
|
||||||
|
/// <param name="PermissionCode">Permission code evaluated.</param>
|
||||||
|
/// <param name="ContextSatisfied">Whether contextual policy requirements were satisfied.</param>
|
||||||
|
public sealed record IdentityPolicyContextResponse(string SubjectId, string PermissionCode, bool ContextSatisfied)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns issued identity token payload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Token">Issued token value.</param>
|
||||||
|
/// <param name="ExpiresInSeconds">Token lifetime in seconds.</param>
|
||||||
|
public sealed record IssueIdentityTokenResponse(string Token, int ExpiresInSeconds) : IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns refreshed identity session token payload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Token">Refreshed token value.</param>
|
||||||
|
/// <param name="ExpiresInSeconds">Token lifetime in seconds.</param>
|
||||||
|
public sealed record RefreshIdentitySessionResponse(string Token, int ExpiresInSeconds)
|
||||||
|
: IIdentityCapabilityContract;
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\BuildingBlock.Identity.Contracts\BuildingBlock.Identity.Contracts.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
using BuildingBlock.Identity.Contracts.Abstractions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Conventions;
|
||||||
|
using BuildingBlock.Identity.Contracts.Requests;
|
||||||
|
using BuildingBlock.Identity.Contracts.Responses;
|
||||||
|
|
||||||
|
namespace BuildingBlock.Identity.Contracts.UnitTests;
|
||||||
|
|
||||||
|
public class ContractShapeTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void IdentityEnvelope_WhenCreated_PreservesValues()
|
||||||
|
{
|
||||||
|
var envelope = new IdentityContractEnvelope("1.0.0", "corr-identity-001");
|
||||||
|
|
||||||
|
Assert.Equal("1.0.0", envelope.ContractVersion);
|
||||||
|
Assert.Equal("corr-identity-001", envelope.CorrelationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IdentityContracts_WhenInstantiated_ImplementMarkerInterface()
|
||||||
|
{
|
||||||
|
IIdentityCapabilityContract issueRequest = new IssueIdentityTokenRequest(
|
||||||
|
"subject-a",
|
||||||
|
"tenant-a",
|
||||||
|
IdentityAuthProvider.AzureAd,
|
||||||
|
"external-token");
|
||||||
|
IIdentityCapabilityContract issueResponse = new IssueIdentityTokenResponse("token-a", 1800);
|
||||||
|
IIdentityCapabilityContract policyRequest = new EvaluateIdentityPolicyRequest(
|
||||||
|
"subject-b",
|
||||||
|
"tenant-b",
|
||||||
|
"identity.token.issue",
|
||||||
|
IdentityAuthProvider.Google);
|
||||||
|
IIdentityCapabilityContract policyResponse = new EvaluateIdentityPolicyResponse("subject-b", "identity.token.issue", true);
|
||||||
|
IIdentityCapabilityContract refreshRequest = new RefreshIdentitySessionRequest(
|
||||||
|
"refresh-a",
|
||||||
|
"corr-refresh",
|
||||||
|
IdentityAuthProvider.InternalJwt);
|
||||||
|
IIdentityCapabilityContract refreshResponse = new RefreshIdentitySessionResponse("token-b", 900);
|
||||||
|
IIdentityCapabilityContract exchangeRequest = new ExchangeIdentityProviderTokenRequest(
|
||||||
|
"tenant-c",
|
||||||
|
IdentityAuthProvider.AzureAd,
|
||||||
|
"provider-token",
|
||||||
|
"corr-exchange");
|
||||||
|
IIdentityCapabilityContract exchangeResponse = new ExchangeIdentityProviderTokenResponse(
|
||||||
|
"subject-c",
|
||||||
|
"tenant-c",
|
||||||
|
IdentityAuthProvider.AzureAd,
|
||||||
|
true);
|
||||||
|
|
||||||
|
Assert.NotNull(issueRequest);
|
||||||
|
Assert.NotNull(issueResponse);
|
||||||
|
Assert.NotNull(policyRequest);
|
||||||
|
Assert.NotNull(policyResponse);
|
||||||
|
Assert.NotNull(refreshRequest);
|
||||||
|
Assert.NotNull(refreshResponse);
|
||||||
|
Assert.NotNull(exchangeRequest);
|
||||||
|
Assert.NotNull(exchangeResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IssueIdentityTokenRequest_WhenProviderSpecified_PreservesProviderMetadata()
|
||||||
|
{
|
||||||
|
var request = new IssueIdentityTokenRequest(
|
||||||
|
"subject-1",
|
||||||
|
"tenant-1",
|
||||||
|
IdentityAuthProvider.Google,
|
||||||
|
"google-token");
|
||||||
|
|
||||||
|
Assert.Equal(IdentityAuthProvider.Google, request.Provider);
|
||||||
|
Assert.Equal("google-token", request.ExternalToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user