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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1353,12 +1353,12 @@ jobs:
run: ./crates/agent-channel-proto/dotnet/build.ps1
shell: pwsh

- name: Agent identity tests
run: dotnet test dotnet/AgentIdentity/AgentIdentity.sln
- name: Agent identity authority tests
run: dotnet test dotnet/Devolutions.Agent.Identity.Authority/Devolutions.Agent.Identity.Authority.sln
shell: pwsh

- name: Build agent identity package
run: ./dotnet/AgentIdentity/build.ps1
- name: Build agent identity authority package
run: ./dotnet/Devolutions.Agent.Identity.Authority/build.ps1
shell: pwsh

agent-identity-vectors:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish-libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
strategy:
fail-fast: false
matrix:
library: [ dotnet-client, dotnet-subscriber, utils, pedm-dotnet-client, agent-channel, agent-identity ]
library: [ dotnet-client, dotnet-subscriber, utils, pedm-dotnet-client, agent-channel, agent-identity-authority ]
include:
- library: dotnet-client
libpath: ./devolutions-gateway/openapi/dotnet-client
Expand All @@ -52,8 +52,8 @@ jobs:
libpath: ./crates/devolutions-pedm/openapi/dotnet-client
- library: agent-channel
libpath: ./crates/agent-channel-proto/dotnet
- library: agent-identity
libpath: ./dotnet/AgentIdentity
- library: agent-identity-authority
libpath: ./dotnet/Devolutions.Agent.Identity.Authority

steps:
- name: Check out ${{ github.repository }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Reflection;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The types that only request authentication, the channel handshake and the enrollment rules create.
Expand All @@ -13,15 +13,15 @@ public class AuthenticationTypeTests
{
private static readonly Type[] AuthenticationTypes =
[
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
typeof(AuthenticatedIdentity),
// The handshake turns an opening into an identity,
// so an opening built by a caller would yield an identity that no signature check produced.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
typeof(ChannelOpening),
// A new identity's certificate is issued from the decision that creates it,
// so a decision built by a caller would certify a key for an identity that no enrollment created.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
typeof(EnrollmentDecision),
// oracle: mutant a public AuthenticationResult constructor
typeof(AuthenticationResult),
Expand All @@ -39,7 +39,7 @@ public class AuthenticationTypeTests
// The other types carry an identity, the opening that becomes one, or the decision that creates one,
// out of a check.
// Each row's marker names what decides it.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
[Theory]
[MemberData(nameof(AuthenticationTypeData))]
public void TypeHasNoPublicOrProtectedConstructor(Type type)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class RegisteredCertificateTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Globalization;
using System.Security.Cryptography;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The parsing rules of CONTRACT.agent-identity.md §6 step 1, beyond the vectors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The steps of CONTRACT.agent-identity.md §6 after parsing: their order, the certificate rules, the nonce,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Text;
using System.Text.RegularExpressions;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The shared request signature vectors, run as their <c>evaluation</c> field says.
Expand Down Expand Up @@ -114,7 +114,7 @@ public async Task FailingCaseRecordsNoNonce(string name)

// The failure detail goes to host logs, so a detail that echoed the request would carry text the sender chose,
// and a captured signature, into those logs.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Failure details
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Failure details
[Theory]
[MemberData(nameof(FailingCaseNames))]
public async Task FailingCaseDetailHoldsNoRequestData(string name)
Expand Down Expand Up @@ -190,7 +190,7 @@ public async Task OkCaseIdentityIsThatOfTheSigningCertificate(string name)
Assert.Equal(registered.NotBefore, identity.CertificateNotBefore);
Assert.Equal(registered.NotAfter, identity.CertificateNotAfter);
// A renewal acts only for an identity that a renew request proved, so the identity carries its operation.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
Assert.Equal(VectorAuthority.Operation(vector.Endpoint), identity.Operation);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Globalization;

using static Devolutions.AgentIdentity.StructuredField;
using static Devolutions.Agent.Identity.Authority.StructuredField;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The RFC 8941 parser and serializer behind the signature fields.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class AgentMetadataTests
{
Expand Down Expand Up @@ -252,7 +252,7 @@ public void RejectsRepeatedKey()

// The failure detail goes to host logs, so it holds no key or value of the metadata, valid or not,
// since an agent could otherwise write into the authority's logs.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Failure details
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Failure details
[Theory]
[MemberData(nameof(FailureNames))]
public void FailureDetailHoldsNoKeyOrValue(string failure)
Expand All @@ -269,7 +269,7 @@ public void FailureDetailHoldsNoKeyOrValue(string failure)

// The control character is part of the value, so the detail holds neither the character
// nor its code point in a hexadecimal rendering such as U+0007, 0x07, 0x0007 or 0007.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Failure details
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Failure details
[Theory]
[MemberData(nameof(ControlCharacters))]
public void FailureDetailDoesNotNameTheControlCharacter(int codePoint)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class ConfirmRequestBodyTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Google.Protobuf;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class IdentityConfigTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// What a test reads from the result of parsing any of the request bodies.
Expand Down Expand Up @@ -155,7 +155,7 @@ public void RejectsMetadataBeyondTheLimits(string form, string metadata)

// The failure detail goes to host logs, so it holds no key or value of the metadata, valid or not,
// since an agent could otherwise write into the authority's logs.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Failure details
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Failure details
[Theory]
[MemberData(nameof(MetadataFailingAtAnEntry))]
public void FailureDetailHoldsNoMetadataKeyOrValue(string form, string metadata)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The bodies of the successful responses of CONTRACT.agent-identity.md §5,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class CertificateSigningRequestTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

// Each test decodes the issued certificate with the BCL and System.Formats.Asn1, never with the library,
// and checks it against CONTRACT.agent-identity.md §4 and RFC 5280.
Expand Down Expand Up @@ -532,7 +532,7 @@ [new X509BasicConstraintsExtension(false, false, 0, true), CaKeyUsage()]),
// Code that acts for an identity takes it as a type only the library's checks can create;
// for a new identity, that is the enrollment decision that creates it.
// A refusal creates no identity, and a replay returns the identity's current chain rather than a new certificate.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
// oracle: contract docs/agent-identity/CONTRACT.agent-identity.md §token-rules
// oracle: spec Framework Design Guidelines §Validating Arguments
[Theory]
Expand Down Expand Up @@ -566,7 +566,7 @@ public void ThrowsForANullDecision()

// An identity is never taken from a value that a caller sent,
// so no public member that issues a certificate takes an identity ID.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
[Fact]
public void NoPublicMemberIssuesACertificateForAnIdentityId()
{
Expand All @@ -588,7 +588,7 @@ public void NoPublicMemberIssuesACertificateForAnIdentityId()

// Code that acts for an identity takes the identity that the signature check produced.
// The renew request is signed by device-a, whose identity ID the vector file gives.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
// oracle: contract docs/agent-identity/CONTRACT.agent-identity.md §certificates
// oracle: contract docs/agent-identity/CONTRACT.agent-identity.md §conventions
[Fact]
Expand All @@ -607,7 +607,7 @@ public async Task RenewalCertifiesTheKeyOfTheCsrForTheIdentityThatSignedTheRenew
// Code that acts for an identity takes the identity that the signature check produced,
// and only a renew request proves the identity that a renewal acts for.
// An identity that proved its key for another operation never had a renew request accepted for it.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
// oracle: contract docs/agent-identity/CONTRACT.agent-identity.md §renew
// oracle: spec Framework Design Guidelines §Validating Arguments
[Theory]
Expand All @@ -631,7 +631,7 @@ public async Task RenewalThrowsForAnIdentityAuthenticatedForAnotherOperation(

// INTENT.md: a renewal acts for the identity that a renew request proved, and null is no identity;
// the .NET Framework Design Guidelines throw ArgumentNullException for a null argument that is not allowed.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
// oracle: spec Framework Design Guidelines §Validating Arguments
[Theory]
[InlineData(nameof(IdentityCertificateIssuer))]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The CSR key rules of a renew request, CONTRACT.agent-identity.md §5.3.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

using Grpc.Core;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The channel handshake of CONTRACT.agent-identity.md §7.3 steps 3 and 4:
Expand Down Expand Up @@ -325,7 +325,7 @@ public async Task FailureClosesTheStreamWithItsCode(string failure)

// The failure detail goes to host logs, so it holds no key or value of the metadata, valid or not,
// since an agent could otherwise write into the authority's logs.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Failure details
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Failure details
[Theory]
[MemberData(nameof(InvalidMetadataEntryNames))]
public async Task FailureDetailHoldsNoMetadataKeyOrValue(string entry)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The shared channel proof vectors, run through the public API:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using Devolutions.Agent.Channel.V1;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The messages that the authority pushes on an authenticated agent channel stream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Devolutions.Agent.Channel.V1;
using Google.Protobuf;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// The channel opening of CONTRACT.agent-identity.md §7.3 steps 1 and 2:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Reflection;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

// An instance of each type below vouches that its value passed validation,
// so nothing but validation may create one: otherwise a host could pass an unchecked value in its place.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../Devolutions.AgentIdentity/Devolutions.AgentIdentity.csproj" />
<ProjectReference Include="../Devolutions.Agent.Identity.Authority/Devolutions.Agent.Identity.Authority.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

// test-vectors.json csr.<name>.expected_at gives each CSR's outcome at each endpoint:
// `enroll` with a valid token whose `u` is the entry's `enrollment_url`, or any valid token when it has none,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Security.Cryptography;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class EnrollmentAuthorizationTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class EnrollmentRulesTests
{
Expand Down Expand Up @@ -301,7 +301,7 @@ public void CreateIdentityCarriesTheTokenUrlWithoutTrailingSlashes(string stored
}

// Only the decision to create an identity issues a certificate.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Authenticated identity
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Authenticated identity
[Theory]
[InlineData(EnrollmentOutcome.Reject)]
[InlineData(EnrollmentOutcome.ReturnExistingIdentity)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

/// <summary>
/// Checks that a text reveals no part of an enrollment token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Security.Cryptography;
using System.Text.Json;

namespace Devolutions.AgentIdentity.Tests;
namespace Devolutions.Agent.Identity.Authority.Tests;

public class EnrollmentTokenTests
{
Expand Down Expand Up @@ -99,7 +99,7 @@ public void CreatePutsTheProductBaseUrlInTheBag(string productBaseUrl)
EnrollmentToken token = EnrollmentToken.Create(productBaseUrl, new ScriptedRandomNumberGenerator(SecretBytes));

// The bag of a token the library creates holds `u` alone.
// oracle: intent dotnet/AgentIdentity/INTENT.md §Enrollment tokens
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Enrollment tokens
Assert.Equal(("u", productBaseUrl), Assert.Single(BagMembers(token)));
}

Expand Down Expand Up @@ -172,7 +172,7 @@ public void CreateRejectsAnotherUrl(string productBaseUrl)
// A 3025-byte URL makes a 3033-byte bag object, a 4044-character bag and a 4095-byte token.
// One more byte makes a 4046-character bag and a 4097-byte token, since no base64url text has 4045 characters.
// oracle: contract docs/agent-identity/CONTRACT.agent-identity.md §enrollment-token
// oracle: intent dotnet/AgentIdentity/INTENT.md §Enrollment tokens
// oracle: intent dotnet/Devolutions.Agent.Identity.Authority/INTENT.md §Enrollment tokens
[Fact]
public void CreateAcceptsTheLongestUrlThatFits()
{
Expand Down
Loading
Loading