merge(identity): integrate identity contracts baseline
This commit is contained in:
commit
3bb0ce47ef
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,8 @@
|
||||
.tasks/
|
||||
.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 context contracts | Contracts/Context | Keep field naming stable for compatibility window |
|
||||
| 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
|
||||
- Current Thalos namespaces are mapped to `BuildingBlock.Identity.Contracts.*`.
|
||||
@ -18,3 +19,4 @@
|
||||
2. Add compatibility bridge in Thalos consumers.
|
||||
3. Migrate service consumers first, then BFF consumers.
|
||||
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