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

Consumer API: Prevent creation and updates to relationships where peer is in status "ToBeDeleted" #695

Merged
Show file tree
Hide file tree
Changes from 7 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
6 changes: 6 additions & 0 deletions BuildingBlocks/src/Tooling/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Text.RegularExpressions;

namespace Backbone.Tooling.Extensions;
Expand All @@ -20,4 +21,9 @@ public static bool MatchesRegex(this string text, string regexString)
var regex = new Regex(regexString);
return regex.IsMatch(text);
}

public static byte[] GetBytes(this string text)
{
return Encoding.UTF8.GetBytes(text);
}
}
104 changes: 52 additions & 52 deletions ConsumerApi.Tests.Integration/ConsumerApi.Tests.Integration.csproj
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,58 +1,58 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>
<PropertyGroup>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1" />
<PackageReference Include="NJsonSchema.NewtonsoftJson" Version="11.0.0" />
<PackageReference Include="ReHackt.Extensions.Options.Validation" Version="8.0.2" />
<PackageReference Include="SolidToken.SpecFlow.DependencyInjection" Version="3.9.3" />
<PackageReference Include="SpecFlow.Plus.LivingDocPlugin" Version="3.9.57" />
<PackageReference Include="SpecFlow.NUnit" Version="3.9.74" />
<PackageReference Include="nunit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1" />
<PackageReference Include="NJsonSchema.NewtonsoftJson" Version="11.0.0" />
<PackageReference Include="ReHackt.Extensions.Options.Validation" Version="8.0.2" />
<PackageReference Include="SolidToken.SpecFlow.DependencyInjection" Version="3.9.3" />
<PackageReference Include="SpecFlow.Plus.LivingDocPlugin" Version="3.9.57" />
<PackageReference Include="SpecFlow.NUnit" Version="3.9.74" />
<PackageReference Include="nunit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BuildingBlocks\src\Crypto\Crypto.csproj" />
<ProjectReference Include="..\ConsumerApi.Sdk\ConsumerApi.Sdk.csproj" />
<ProjectReference Include="..\ConsumerApi\ConsumerApi.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BuildingBlocks\src\Crypto\Crypto.csproj" />
<ProjectReference Include="..\ConsumerApi.Sdk\ConsumerApi.Sdk.csproj" />
<ProjectReference Include="..\ConsumerApi\ConsumerApi.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="api.appsettings.local.override.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="specflow.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<None Update="api.appsettings.local.override.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="specflow.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<SpecFlowFeatureFiles Update="Features\Challenges\POST.feature">
<Visible>$(UsingMicrosoftNETSdk)</Visible>
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
</SpecFlowFeatureFiles>
<SpecFlowFeatureFiles Update="Features\Challenges\{id}\GET.feature">
<Visible>$(UsingMicrosoftNETSdk)</Visible>
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
</SpecFlowFeatureFiles>
</ItemGroup>
<ItemGroup>
<SpecFlowFeatureFiles Update="Features\Challenges\POST.feature">
<Visible>$(UsingMicrosoftNETSdk)</Visible>
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
</SpecFlowFeatureFiles>
<SpecFlowFeatureFiles Update="Features\Challenges\{id}\GET.feature">
<Visible>$(UsingMicrosoftNETSdk)</Visible>
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
</SpecFlowFeatureFiles>
</ItemGroup>
</Project>
34 changes: 17 additions & 17 deletions ConsumerApi.Tests.Integration/Features/Relationships/POST.feature
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,60 @@ User creates a Relationship

Scenario: Creating a Relationship
Given Identities i1 and i2
And a Relationship Template rt created by i1
When a POST request is sent to the /Relationships endpoint by i2 with rt.id
And a Relationship Template rt created by i2
When a POST request is sent to the /Relationships endpoint by i1 with rt.id
Then the response status code is 201 (Created)
And the response contains a Relationship

Scenario: Creating a Relationship with Identity "ToBeDeleted"
Scenario: Creating a Relationship to an Identity in status "ToBeDeleted"
Given Identities i1 and i2
And a Relationship Template rt created by i1
And i1 is in status "ToBeDeleted"
When a POST request is sent to the /Relationships endpoint by i2 with rt.id
And a Relationship Template rt created by i2
And i2 is in status "ToBeDeleted"
When a POST request is sent to the /Relationships endpoint by i1 with rt.id
Then the response status code is 400 (Bad Request)
And the response content contains an error with the error code "error.platform.validation.relationship.peerIsToBeDeleted"

Scenario: Accept Relationship Change
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
And a pending Relationship between i1 and i2 created by i1
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Accept endpoint by i1
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Then the response status code is 200 (OK)
And the response contains an AcceptRelationshipChangeResponse

Scenario: Accept Relationship Change with Identity "ToBeDeleted"
Scenario: Accept Relationship Change to an Identity in status "ToBeDeleted"
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
And a pending Relationship between i1 and i2 created by i1
And i1 is in status "ToBeDeleted"
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Accept endpoint by i1
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Then the response status code is 400 (Bad Request)
And the response content contains an error with the error code "error.platform.validation.relationship.peerIsToBeDeleted"

Scenario: Reject Relationship Change
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
And a pending Relationship between i1 and i2 created by i1
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Reject endpoint by i1
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Then the response status code is 200 (OK)
And the response contains an RejectRelationshipChangeResponse

Scenario: Reject Relationship Change with Identity "ToBeDeleted"
Scenario: Reject Relationship Change to an Identity in status "ToBeDeleted"
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
And a pending Relationship between i1 and i2 created by i1
And i1 is in status "ToBeDeleted"
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Reject endpoint by i1
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Then the response status code is 400 (Bad Request)
And the response content contains an error with the error code "error.platform.validation.relationship.peerIsToBeDeleted"

Scenario: Revoke Relationship Change
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i2
And a pending Relationship between i1 and i2 created by i2
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i1
daniel-almeida-konkconsulting marked this conversation as resolved.
Show resolved Hide resolved
Then the response status code is 200 (OK)
And the response contains an RevokeRelationshipChangeResponse

Scenario: Revoke Relationship Change with Identity "ToBeDeleted"
Scenario: Revoke Relationship Change to an Identity in status "ToBeDeleted"
Given Identities i1 and i2
And a pending Relationship between i1 and i2 initiated by i1
And a pending Relationship between i1 and i2 created by i1
And i1 is in status "ToBeDeleted"
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i2
When a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i1
Then the response status code is 400 (Bad Request)
And the response content contains an error with the error code "error.platform.validation.relationship.peerIsToBeDeleted"
8 changes: 4 additions & 4 deletions ConsumerApi.Tests.Integration/Helpers/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types.Requests;
using Backbone.ConsumerApi.Sdk.Endpoints.RelationshipTemplates.Types.Requests;
using Backbone.ConsumerApi.Tests.Integration.Extensions;
using Backbone.Crypto;
using Backbone.Tooling.Extensions;

namespace Backbone.ConsumerApi.Tests.Integration.Helpers;

Expand All @@ -12,7 +12,7 @@ public static async Task EstablishRelationshipBetween(Client client1, Client cli
{
var createRelationshipTemplateRequest = new CreateRelationshipTemplateRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};

var relationshipTemplateResponse = await client1.RelationshipTemplates.CreateTemplate(createRelationshipTemplateRequest);
Expand All @@ -21,15 +21,15 @@ public static async Task EstablishRelationshipBetween(Client client1, Client cli
var createRelationshipRequest = new CreateRelationshipRequest
{
RelationshipTemplateId = relationshipTemplateResponse.Result!.Id,
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};

var createRelationshipResponse = await client2.Relationships.CreateRelationship(createRelationshipRequest);
createRelationshipResponse.Should().BeASuccess();

var completeRelationshipChangeRequest = new CompleteRelationshipChangeRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};
var acceptRelationChangeResponse =
await client1.Relationships.AcceptChange(createRelationshipResponse.Result!.Id, createRelationshipResponse.Result.Changes.First().Id, completeRelationshipChangeRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Backbone.ConsumerApi.Tests.Integration.Configuration;
using Backbone.ConsumerApi.Tests.Integration.Extensions;
using Backbone.ConsumerApi.Tests.Integration.Support;
using Backbone.Crypto;
using Backbone.Tooling.Extensions;
using Microsoft.Extensions.Options;

namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions;
Expand Down Expand Up @@ -42,14 +42,24 @@ public async Task GivenIdentitiesI1AndI2()
_client2 = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD);
}

[Given("a Relationship Template rt created by i1")]
public async Task GivenARelationshipTemplateRtCreatedByI1()
[Given("a Relationship Template rt created by i2")]
public async Task GivenARelationshipTemplateRtCreatedByI2()
{
_relationshipTemplateResponse = await CreateRelationshipTemplate(_client1);
_relationshipTemplateResponse = await CreateRelationshipTemplate(_client2);
}

[Given("a pending Relationship between i1 and i2 initiated by i1")]
public async Task GivenAPendingRelationshipBetweenI1AndI2InitiatedByI1()
[Given("a pending Relationship between i1 and i2 created by i2")]
public async Task GivenAPendingRelationshipBetweenI1AndI2CreatedByI2()
{
var relationshipTemplateResponse = await CreateRelationshipTemplate(_client2);
var createRelationshipResponse = await CreateRelationship(_client1, relationshipTemplateResponse.Result!.Id);

_relationshipId = createRelationshipResponse.Result!.Id;
_relationshipChangeId = createRelationshipResponse.Result!.Changes.First().Id;
}

[Given("a pending Relationship between i1 and i2 created by i1")]
public async Task GivenAPendingRelationshipBetweenI1AndI2CreatedByI1()
{
var relationshipTemplateResponse = await CreateRelationshipTemplate(_client1);
var createRelationshipResponse = await CreateRelationship(_client2, relationshipTemplateResponse.Result!.Id);
Expand All @@ -58,25 +68,32 @@ public async Task GivenAPendingRelationshipBetweenI1AndI2InitiatedByI1()
_relationshipChangeId = createRelationshipResponse!.Result!.Changes.First().Id;
}

[Given("i2 is in status \"ToBeDeleted\"")]
public async Task GivenIdentityI2IsToBeDeleted()
{
var startDeletionProcessResponse = await _client2.Identities.StartDeletionProcess();
startDeletionProcessResponse.Should().BeASuccess();
}

[Given("i1 is in status \"ToBeDeleted\"")]
public async Task GivenIdentityI1IsToBeDeleted()
{
var startDeletionProcessResponse = await _client1.Identities.StartDeletionProcess();
startDeletionProcessResponse.Should().BeASuccess();
}

[When("a POST request is sent to the /Relationships endpoint by i2 with rt.id")]
public async Task WhenAPostRequestIsSentToTheRelationshipsEndpointByI2With()
[When("a POST request is sent to the /Relationships endpoint by i1 with rt.id")]
public async Task WhenAPostRequestIsSentToTheRelationshipsEndpointByI1With()
{
_createRelationshipResponse = await CreateRelationship(_client2, _relationshipTemplateResponse!.Result!.Id);
_createRelationshipResponse = await CreateRelationship(_client1, _relationshipTemplateResponse!.Result!.Id);
}

[When("a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Accept endpoint by i1")]
public async Task WhenAPostRequestIsSentToTheAcceptRelationshipChangeEndpointByI1()
{
var completeRelationshipChangeRequest = new CompleteRelationshipChangeRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};
_acceptRelationshipChangeResponse = await _client1.Relationships.AcceptChange(_relationshipId, _relationshipChangeId, completeRelationshipChangeRequest);
}
Expand All @@ -86,19 +103,19 @@ public async Task WhenAPostRequestIsSentToTheRejectRelationshipChangeEndpointByI
{
var completeRelationshipChangeRequest = new CompleteRelationshipChangeRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};
_rejectRelationshipChangeResponse = await _client1.Relationships.RejectChange(_relationshipId, _relationshipChangeId, completeRelationshipChangeRequest);
}

[When("a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i2")]
[When("a POST request is sent to the /Relationships/{r.Id}/Changes/{r.Changes.Id}/Revoke endpoint by i1")]
public async Task WhenAPostRequestIsSentToTheRevokeRelationshipChangeEndpointByI2()
{
var completeRelationshipChangeRequest = new CompleteRelationshipChangeRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};
_revokeRelationshipChangeResponse = await _client2.Relationships.RevokeChange(_relationshipId, _relationshipChangeId, completeRelationshipChangeRequest);
_revokeRelationshipChangeResponse = await _client1.Relationships.RevokeChange(_relationshipId, _relationshipChangeId, completeRelationshipChangeRequest);
}

[Then(@"the response status code is (\d\d\d) \(.+\)")]
Expand Down Expand Up @@ -177,7 +194,7 @@ private async Task<ApiResponse<CreateRelationshipTemplateResponse>> CreateRelati
{
var createRelationshipTemplateRequest = new CreateRelationshipTemplateRequest
{
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};

return await client.RelationshipTemplates.CreateTemplate(createRelationshipTemplateRequest);
Expand All @@ -188,7 +205,7 @@ private async Task<ApiResponse<RelationshipMetadata>> CreateRelationship(Client
var createRelationshipRequest = new CreateRelationshipRequest
{
RelationshipTemplateId = relationshipTemplateId,
Content = ConvertibleString.FromUtf8("AAA").BytesRepresentation
Content = "AAA".GetBytes()
};

return await client.Relationships.CreateRelationship(createRelationshipRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.9.1" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.1" />
<PackageReference Include="OpenIddict.Core" Version="5.6.0"/>
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="5.6.0"/>
<PackageReference Include="OpenIddict.Core" Version="5.6.0" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="5.6.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading