Skip to content

Commit

Permalink
Personalized tokens (#796)
Browse files Browse the repository at this point in the history
* refactor: extract common code to BaseStepDefinitions file

* feat: add forIdentity field

* fix: windows add_migration command not working

* feat: personalized tokens support for GET /Tokens

* chore: fix formatting

* fix: Backbone.Modules.Tokens.Application.Tokens.Commands.CreateToken.CreateTokenCommand was missing required properties, including the following: forIdentity

* feat: add sql server migrations

* fix: CreateTokenCommand was missing required properties, including the following: forIdentity

* chore: fix formatting

* Update Applications/ConsumerApi/test/ConsumerApi.Tests.Integration/Features/Tokens/GET.feature

Co-authored-by: Nikola Dmitrasinovic <[email protected]>

* chore: code review changes

* chore: update other script files for windows

* chore: review changes

* test: Token.CanBeCollectedBy

* feat: remove conditional statement

* fix: remove null suppressing

* chore: rename field

* chore: rename input param

* chore: rename input param

* chore: rename var

* chore: remove unnecessary null check

* chore: renema param

* fix: use TestDataGenerator to get identity address

* feat: extract method

* refactor: improve assertion

* refactor: improve code structure

* refactor: improve code structure

* fix: remove imput param

* test: add integration test

* fix: filter tokens by owner

* fix: integration test

* feat: remove FindAllOfOwner()

* feat: add ForIdentity prop to DTO

* chore: fix typo

* refactor: improve code structure of TokensRepository

* refactor: improve Find() of TokensRepository

* Merge branch 'main' into NMSHDB-180-personalized-tokens

* feat: introduce validation for ForIdentity prop

* chore: remove blank lines

* test: really small readability improvement

* fix: validation

* test: improve unit test for expression

* chore: remove unnecessary check

* test: add for create token validator

* chore: fix formatting issues

* Update Modules/Tokens/test/Tokens.Application.Tests/Tests/Tokens/CreateToken/ValidatorTests.cs

Co-authored-by: Timo Notheisen <[email protected]>

* format: improve crete token test structure

* refactor: improve code structure of ValidatorTests

* chore: rename param

* chore: fix formatting issues

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Nikola Dmitrasinovic <[email protected]>
Co-authored-by: Nikola Dmitrasinovic <[email protected]>
Co-authored-by: Timo Notheisen <[email protected]>
Co-authored-by: Timo Notheisen <[email protected]>
  • Loading branch information
6 people authored Aug 30, 2024
1 parent 8498a97 commit 715afeb
Show file tree
Hide file tree
Showing 29 changed files with 591 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.8" />
<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.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,30 @@ Scenario: Requesting an own and peer Token
When a GET request is sent to the Tokens endpoint with a list containing t.Id, p.Id
Then the response status code is 200 (OK)
And the response contains both Tokens

Scenario: Requesting a list of Tokens contains tokens with forIdentity which were created by me
Given Identities i1 and i2
And a Token t created by i1 where forIdentity is the address of i2
When i1 sends a GET request to the /Tokens endpoint and passes t.id
Then the response status code is 200 (Ok)
And the response contains t

Scenario: Requesting a list of Tokens contains tokens with forIdentity which were created for me
Given Identities i1 and i2
And a Token t created by i1 where forIdentity is the address of i2
When i2 sends a GET request to the /Tokens endpoint and passes t.id
Then the response status code is 200 (Ok)
And the response contains t

Scenario: Requesting a list of Tokens contains tokens which can be collected by me
Given Identities i1 and i2
And a Token t created by i1 where forIdentity is the address of i2
When i1 sends a GET request to the /Tokens endpoint
Then the response status code is 200 (Ok)
And the response contains t

Scenario: Requesting a list of Tokens does not contain tokens with forIdentity which were created for someone else
Given Identities i1, i2 and i3
And a Token t created by i1 where forIdentity is the address of i2
When i3 sends a GET request to the /Tokens endpoint and passes t.id
Then the response does not contain t
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,31 @@ Scenario: Requesting a nonexistent Token as an authenticated user
# | TOKnotenoughchars | Less than 20 characters |
# | TOK_frfssd_fdfdsed#_ | Contains invalid characters |
# | POKfdjfdjflndjkfndjk | Does not have TOK prefix |


Scenario: Requesting a token with a specific forIdentity field using the recipient's address as the requester
Given Identities i1 and i2
And a Token t created by i1 where forIdentity is the address of i2
When i2 sends a GET request to the /Tokens/{id} endpoint with t.id
Then the response status code is 200 (Ok)
And the response contains t

Scenario: Requesting a token with a specific forIdentity field using the creator's address as the requester
Given Identities i1 and i2
And a Token t created by i1 where forIdentity is the address of i2
When i1 sends a GET request to the /Tokens/{id} endpoint with t.id
Then the response status code is 200 (Ok)
And the response contains t

Scenario: Requesting a token with a specific forIdentity field using the another address as the requester
Given Identities i1, i2 and i3
And a Token t created by i1 where forIdentity is the address of i2
When i3 sends a GET request to the /Tokens/{id} endpoint with t.id
Then the response status code is 404 (Not Found)

Scenario: Requesting a token with a specific forIdentity field using the an anonymous user as the requester
Given Identities i1 and i2
And the user is unauthenticated
And a Token t created by i1 where forIdentity is the address of i2
When a GET request is sent to the Tokens/{id} endpoint with t.Id
Then the response status code is 404 (Not Found)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Backbone.ConsumerApi.Sdk;
using Backbone.ConsumerApi.Sdk.Authentication;
using Backbone.ConsumerApi.Tests.Integration.Configuration;
using Backbone.ConsumerApi.Tests.Integration.Support;
using Microsoft.Extensions.Options;

namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions;

internal class BaseStepDefinitions
{
internal readonly Dictionary<string, Client> Identities = new();
internal readonly HttpClient HttpClient;
internal readonly ClientCredentials ClientCredentials;

public BaseStepDefinitions(HttpClientFactory factory, IOptions<HttpConfiguration> httpConfiguration)
{
HttpClient = factory.CreateClient();
ClientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret);
}

#region Given

[Given(@"Identities (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public void Given2Identities(string identity1Name, string identity2Name)
{
Identities[identity1Name] = Client.CreateForNewIdentity(HttpClient, ClientCredentials, Constants.DEVICE_PASSWORD).Result;
Identities[identity2Name] = Client.CreateForNewIdentity(HttpClient, ClientCredentials, Constants.DEVICE_PASSWORD).Result;
}

[Given(@"Identities (i[a-zA-Z0-9]*), (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public void Given3Identities(string identity1Name, string identity2Name, string identity3Name)
{
Identities[identity1Name] = Client.CreateForNewIdentity(HttpClient, ClientCredentials, Constants.DEVICE_PASSWORD).Result;
Identities[identity2Name] = Client.CreateForNewIdentity(HttpClient, ClientCredentials, Constants.DEVICE_PASSWORD).Result;
Identities[identity3Name] = Client.CreateForNewIdentity(HttpClient, ClientCredentials, Constants.DEVICE_PASSWORD).Result;
}

#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Backbone.ConsumerApi.Tests.Integration.Configuration;
using Backbone.ConsumerApi.Tests.Integration.Extensions;
using Backbone.ConsumerApi.Tests.Integration.Helpers;
using Backbone.ConsumerApi.Tests.Integration.Support;
using Backbone.Crypto;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.UnitTestTools.Data;
Expand All @@ -20,63 +19,40 @@ namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions;
[Binding]
[Scope(Feature = "POST Message")]
[Scope(Feature = "GET Messages")]
internal class MessagesStepDefinitions
internal class MessagesStepDefinitions : BaseStepDefinitions
{
private readonly ClientCredentials _clientCredentials;
private readonly HttpClient _httpClient;

private readonly Dictionary<string, Client> _identities = new();
private readonly Dictionary<string, Relationship> _relationships = new();
private readonly Dictionary<string, Message> _messages = new();
private ApiResponse<ListMessagesResponse>? _getMessagesResponse;
private ApiResponse<SendMessageResponse>? _sendMessageResponse;
private IResponse? _whenResponse;

public MessagesStepDefinitions(HttpClientFactory factory, IOptions<HttpConfiguration> httpConfiguration)
{
_httpClient = factory.CreateClient();
_clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret);
}
public MessagesStepDefinitions(HttpClientFactory factory, IOptions<HttpConfiguration> httpConfiguration) : base(factory, httpConfiguration) { }

#region Given

[Given(@"Identities (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public void Given2Identities(string identity1Name, string identity2Name)
{
_identities[identity1Name] = Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD).Result;
_identities[identity2Name] = Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD).Result;
}

[Given(@"Identities (i[a-zA-Z0-9]*), (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public void Given3Identities(string identity1Name, string identity2Name, string identity3Name)
{
_identities[identity1Name] = Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD).Result;
_identities[identity2Name] = Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD).Result;
_identities[identity3Name] = Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD).Result;
}

[Given(@"a Relationship (r[a-zA-Z0-9]*) between (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public async Task GivenARelationshipRBetweenIAndI(string relationshipName, string identity1Name, string identity2Name)
{
var relationship = await Utils.EstablishRelationshipBetween(_identities[identity1Name], _identities[identity2Name]);
var relationship = await Utils.EstablishRelationshipBetween(Identities[identity1Name], Identities[identity2Name]);
_relationships[relationshipName] = relationship;
}

[Given(@"(i[a-zA-Z0-9]*) has sent a Message (m[a-zA-Z0-9]*) to (i[a-zA-Z0-9]*)")]
public async Task GivenIHasSentMessageTo1Recipient(string senderName, string messageName, string recipientName)
{
var sender = _identities[senderName];
var recipient = _identities[recipientName];
var sender = Identities[senderName];
var recipient = Identities[recipientName];

_messages[messageName] = await Utils.SendMessage(sender, recipient);
}

[Given(@"(i[a-zA-Z0-9]*) has sent a Message (m[a-zA-Z0-9]*) to (i[a-zA-Z0-9]*) and (i[a-zA-Z0-9]*)")]
public async Task GivenIHasSentMessageTo2Recipients(string senderName, string messageName, string recipient1Name, string recipient2Name)
{
var sender = _identities[senderName];
var recipient1 = _identities[recipient1Name];
var recipient2 = _identities[recipient2Name];
var sender = Identities[senderName];
var recipient1 = Identities[recipient1Name];
var recipient2 = Identities[recipient2Name];

_messages[messageName] = await Utils.SendMessage(sender, recipient1, recipient2);
}
Expand All @@ -85,7 +61,7 @@ public async Task GivenIHasSentMessageTo2Recipients(string senderName, string me
public async Task GivenRIsTerminated(string terminatorName, string relationshipName)
{
var relationship = _relationships[relationshipName];
var terminator = _identities[terminatorName];
var terminator = Identities[terminatorName];

var terminateRelationshipResponse = await terminator.Relationships.TerminateRelationship(relationship.Id);
terminateRelationshipResponse.Should().BeASuccess();
Expand All @@ -94,7 +70,7 @@ public async Task GivenRIsTerminated(string terminatorName, string relationshipN
[Given(@"(i[a-zA-Z0-9]*) has decomposed (r[a-zA-Z0-9]*)")]
public async Task GivenIHasDecomposedItsRelationshipToI(string decomposerName, string relationshipName)
{
var decomposer = _identities[decomposerName];
var decomposer = Identities[decomposerName];
var relationship = _relationships[relationshipName];

var decomposeRelationshipResponse = await decomposer.Relationships.DecomposeRelationship(relationship.Id);
Expand All @@ -106,7 +82,7 @@ public async Task GivenIHasDecomposedItsRelationshipToI(string decomposerName, s
[Given("(i[a-zA-Z0-9]*) is in status \"ToBeDeleted\"")]
public async Task GivenIdentityIIsToBeDeleted(string identityName)
{
var identity = _identities[identityName];
var identity = Identities[identityName];
var startDeletionProcessResponse = await identity.Identities.StartDeletionProcess();
startDeletionProcessResponse.Should().BeASuccess();
}
Expand All @@ -118,16 +94,16 @@ public async Task GivenIdentityIIsToBeDeleted(string identityName)
[When(@"(i[a-zA-Z0-9]*) sends a GET request to the /Messages endpoint")]
public async Task WhenISendsAGETRequestToTheMessagesEndpoint(string senderName)
{
var sender = _identities[senderName];
var sender = Identities[senderName];
var getMessagesResponse = await sender.Messages.ListMessages();
_whenResponse = _getMessagesResponse = getMessagesResponse;
}

[When("(i[a-zA-Z0-9]*) sends a POST request to the /Messages endpoint with (i[a-zA-Z0-9]*) as recipient")]
public async Task WhenAPostRequestIsSentToTheMessagesEndpoint(string senderName, string recipientName)
{
var sender = _identities[senderName];
var recipient = _identities[recipientName];
var sender = Identities[senderName];
var recipient = Identities[recipientName];

var sendMessageRequest = new SendMessageRequest
{
Expand Down Expand Up @@ -184,7 +160,7 @@ public void ThenTheResponseContainsTheMessageM(string messageName)
[Then(@"the address of the recipient (i[a-zA-Z0-9]*) is anonymized")]
public void ThenTheAddressOfIIsAnonymized(string anonymizedIdentityName)
{
var addressOfIdentityThatShouldBeAnonymized = _identities[anonymizedIdentityName].IdentityData!.Address;
var addressOfIdentityThatShouldBeAnonymized = Identities[anonymizedIdentityName].IdentityData!.Address;

ThrowIfNull(_getMessagesResponse);

Expand Down Expand Up @@ -225,7 +201,7 @@ public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCo
[Then(@"the error contains a list of Identities to be deleted that includes (i[a-zA-Z0-9]*)")]
public void ThenTheErrorContainsAListOfIdentitiesToBeDeletedThatIncludesIdentityI2(string includedIdentityName)
{
var includedIdentity = _identities[includedIdentityName];
var includedIdentity = Identities[includedIdentityName];
var data = _sendMessageResponse!.Error!.Data?.As<PeersToBeDeletedErrorData>();
data.Should().NotBeNull();
data!.PeersToBeDeleted.Contains(includedIdentity.IdentityData!.Address).Should().BeTrue();
Expand Down
Loading

0 comments on commit 715afeb

Please sign in to comment.