Skip to content

Commit

Permalink
fix(osp): applied regex validation on uniqueIds param
Browse files Browse the repository at this point in the history
  • Loading branch information
tfjanjua committed Feb 6, 2025
1 parent 54fbbe2 commit 460d738
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 4 deletions.
5 changes: 5 additions & 0 deletions src/framework/Framework.Models/ValidationExpressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ public static class ValidationExpressions
/// </remarks>
public const string Company = @"^(?!.*\s$)([\p{L}\u0E00-\u0E7F\d\p{Sc}@%*+_\-/\\,.:;=<>!?&^#'\x22()[\]]\s?){1,160}$";
public const string ExternalCertificateNumber = @"^[a-zA-Z0-9]{0,36}$";
public const string COMMERCIAL_REG_NUMBER = "^(?!.*\\s$)([A-Za-z0-9](\\.|\\s|-)?){4,21}$";
public const string VAT_ID = "^(?!.*\\s$)([A-Za-z0-9](\\.|\\s|-|\\/)?){5,18}$";
public const string LEI_CODE = "^[A-Za-z0-9]{20}$";
public const string VIES = "^[A-Z]{2}[0-9A-Za-z+*.]{2,12}$";
public const string EORI = "^[A-Z]{2}[A-Za-z0-9]{1,15}$";
}
25 changes: 25 additions & 0 deletions src/registration/Registration.Common/RegistrationValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
********************************************************************************/

using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Linq;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Org.Eclipse.TractusX.Portal.Backend.Registration.Common.ErrorHandling;
Expand All @@ -28,6 +29,11 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Registration.Common;
public static class RegistrationValidation
{
private static readonly Regex BpnRegex = new(ValidationExpressions.Bpn, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex CommercialRegNumRegex = new(ValidationExpressions.COMMERCIAL_REG_NUMBER, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex VatIdRegex = new(ValidationExpressions.VAT_ID, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex LeiCodeRegex = new(ValidationExpressions.LEI_CODE, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex ViesRegex = new(ValidationExpressions.VIES, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex EoriRegex = new(ValidationExpressions.EORI, RegexOptions.Compiled, TimeSpan.FromSeconds(1));

public static void ValidateData(this RegistrationData data)
{
Expand Down Expand Up @@ -72,6 +78,14 @@ public static void ValidateData(this RegistrationData data)
RegistrationValidationErrors.UNIQUE_IDS_NO_DUPLICATE_VALUES,
Enumerable.Repeat(new ErrorParameter("duplicateValues", string.Join(", ", duplicateIds.Select(uniqueId => uniqueId.UniqueIdentifierId))), 1));
}

data.UniqueIds.Where(uniqueId => IsInvalidValueByUniqueIdentifier(uniqueId.Value, uniqueId.UniqueIdentifierId))
.IfAny(invalidUniqueIdentifiersValues =>
{
throw new ControllerArgumentException(
$"Invalid value of uniqueIds: '{string.Join(", ", invalidUniqueIdentifiersValues.Select(uniqueId => uniqueId.UniqueIdentifierId))}'",
nameof(data.UniqueIds));
});
}

public static async Task ValidateDatabaseData(this RegistrationData data, Func<string, Task<bool>> checkBpn, Func<string, Task<bool>> checkCountryExistByAlpha2Code, Func<string, IEnumerable<UniqueIdentifierId>, Task<(bool IsValidCountry, IEnumerable<UniqueIdentifierId> UniqueIdentifierIds)>> getCountryAssignedIdentifiers, bool checkBpnAlreadyExists)
Expand Down Expand Up @@ -116,4 +130,15 @@ public static async Task ValidateDatabaseData(this RegistrationData data, Func<s
}
}
}

private static bool IsInvalidValueByUniqueIdentifier(string value, UniqueIdentifierId uniqueIdentifierId) =>
uniqueIdentifierId switch
{
UniqueIdentifierId.COMMERCIAL_REG_NUMBER => !CommercialRegNumRegex.IsMatch(value),
UniqueIdentifierId.VAT_ID => !VatIdRegex.IsMatch(value),
UniqueIdentifierId.LEI_CODE => !LeiCodeRegex.IsMatch(value),
UniqueIdentifierId.VIES => !ViesRegex.IsMatch(value),
UniqueIdentifierId.EORI => !EoriRegex.IsMatch(value),
_ => throw new ControllerArgumentException($"Unique identifier: {uniqueIdentifierId} is not available in the system", nameof(uniqueIdentifierId))
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Tests.Busin
public class NetworkBusinessLogicTests
{
private const string Bpn = "BPNL00000001TEST";
private const string VatId = "DE123456789";
private static readonly string ExistingExternalId = Guid.NewGuid().ToString();
private static readonly Guid CompanyId = new("95c4339e-e087-4cd2-a5b8-44d385e64630");
private static readonly Guid UserRoleId = Guid.NewGuid();
Expand Down Expand Up @@ -139,13 +140,33 @@ public async Task HandlePartnerRegistration_WithInvalidBusinessPartnerNumber_Thr
ex.Message.Should().Be(RegistrationValidationErrors.BPN_INVALID.ToString());
}

[Fact]
public async Task HandlePartnerRegistration_WithInvalidUniqueId_ThrowsControllerArgumentException()
{
// Arrange
var data = _fixture.Build<PartnerRegistrationData>()
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, "123"), new CompanyUniqueIdData(UniqueIdentifierId.COMMERCIAL_REG_NUMBER, "12")])
.Create();

// Act
async Task Act() => await _sut.HandlePartnerRegistration(data);

// Assert
var ex = await Assert.ThrowsAsync<ControllerArgumentException>(Act);
ex.Message.Should().Be("Invalid value of uniqueIds: 'VAT_ID, COMMERCIAL_REG_NUMBER' (Parameter 'UniqueIds')");
ex.ParamName.Should().Be("UniqueIds");
}

[Fact]
public async Task HandlePartnerRegistration_WithoutExistingBusinessPartnerNumber_ThrowsControllerArgumentException()
{
// Arrange
var data = _fixture.Build<PartnerRegistrationData>()
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.BusinessPartnerNumber, "BPNL00000001FAIL")
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -164,6 +185,7 @@ public async Task HandlePartnerRegistration_WithInvalidCompanyUserRole_ThrowsCon
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.CompanyRoles, Enumerable.Empty<CompanyRoleId>())
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -185,6 +207,7 @@ public async Task HandlePartnerRegistration_WithInvalidEmail_ThrowsControllerArg
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, Guid.NewGuid().ToString(), "test", "Test", "test", email) })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -204,6 +227,7 @@ public async Task HandlePartnerRegistration_WithInvalidFirstnameEmail_ThrowsCont
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, Guid.NewGuid().ToString(), "test", firstName, "test", "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -223,6 +247,7 @@ public async Task HandlePartnerRegistration_WithInvalidLastnameEmail_ThrowsContr
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, Guid.NewGuid().ToString(), "test", "test", lastname, "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -242,6 +267,7 @@ public async Task HandlePartnerRegistration_WithExistingExternalId_ThrowsControl
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, Guid.NewGuid().ToString(), "test", "test", "test", "test@email.com") })
.With(x => x.ExternalId, ExistingExternalId)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -261,6 +287,7 @@ public async Task HandlePartnerRegistration_WithInvalidCountryCode_ThrowsControl
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.UserDetails, new[] { new UserDetailData(null, Guid.NewGuid().ToString(), "test", "test", "test", "test@email.com") })
.With(x => x.CountryAlpha2Code, "XX")
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -280,6 +307,7 @@ public async Task HandlePartnerRegistration_WithNoIdpIdSetAndNoManagedIdps_Throw
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, "123", "test", "test", "test", "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();
A.CallTo(() => _identity.CompanyId).Returns(NoIdpCompanyId);

Expand All @@ -300,6 +328,7 @@ public async Task HandlePartnerRegistration_WithNoIdpIdSetAndMultipleManagedIdps
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(null, "123", "test", "test", "test", "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();
A.CallTo(() => _identity.CompanyId).Returns(MultiIdpCompanyId);

Expand All @@ -322,6 +351,7 @@ public async Task HandlePartnerRegistration_WithNotExistingIdpIdSet_ThrowsContro
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(notExistingIdpId, "123", "test", "test", "test", "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();

// Act
Expand All @@ -341,6 +371,7 @@ public async Task HandlePartnerRegistration_WithInvalidInitialRole_ThrowsConfigu
.With(x => x.BusinessPartnerNumber, Bpn)
.With(x => x.CountryAlpha2Code, "DE")
.With(x => x.UserDetails, new[] { new UserDetailData(IdpId, "123", "test", "test", "test", "test@email.com") })
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, VatId)])
.Create();
A.CallTo(() => _userProvisioningService.GetRoleDatas(A<IEnumerable<UserRoleConfig>>._))
.Throws(new ControllerArgumentException($"invalid roles: clientId: 'cl1', roles: [Company Admin]"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public class RegistrationBusinessLogicTest
private readonly Guid _existingApplicationId;
private readonly string _displayName;
private readonly string _alpha2code;
private readonly string _vatId;
private readonly TestException _error;
private readonly IOptions<RegistrationSettings> _options;
private readonly IStaticDataRepository _staticDataRepository;
Expand Down Expand Up @@ -136,6 +137,7 @@ public RegistrationBusinessLogicTest()
_existingApplicationId = _fixture.Create<Guid>();
_displayName = _fixture.Create<string>();
_alpha2code = "XY";
_vatId = "DE123456789";
_error = _fixture.Create<TestException>();

_processLine =
Expand Down Expand Up @@ -644,6 +646,7 @@ public async Task SetCompanyWithAddressAsync__WithExistingBpn_ModifiesCompany()
.With(x => x.BusinessPartnerNumber, "BPNL00000001TEST")
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();
A.CallTo(() => _companyRepository.CheckBpnExists("BPNL00000001TEST")).Returns(true);

Expand Down Expand Up @@ -707,6 +710,7 @@ public async Task SetCompanyWithAddressAsync__WithCompanyNameChange_ModifiesComp
.With(x => x.BusinessPartnerNumber, "BPNL00000001TEST")
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();

var sut = new RegistrationBusinessLogic(
Expand Down Expand Up @@ -771,6 +775,7 @@ public async Task SetCompanyWithAddressAsync__WithoutCompanyNameChange_ModifiesC
.With(x => x.BusinessPartnerNumber, "BPNL00000001TEST")
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();

var sut = new RegistrationBusinessLogic(
Expand Down Expand Up @@ -836,6 +841,7 @@ public async Task SetCompanyWithAddressAsync_ModifyCompany(string? bpn)
.With(x => x.BusinessPartnerNumber, bpn)
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();

var existingData = _fixture.Build<CompanyApplicationDetailData>()
Expand Down Expand Up @@ -903,6 +909,7 @@ public async Task SetCompanyWithAddressAsync_WithoutInitialCompanyAddress_Create
.With(x => x.BusinessPartnerNumber, default(string?))
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();

var existingData = _fixture.Build<CompanyApplicationDetailData>()
Expand Down Expand Up @@ -1001,6 +1008,7 @@ public async Task SetCompanyWithAddressAsync_WithInitialCompanyAddress_ModifyAdd
.With(x => x.BusinessPartnerNumber, default(string?))
.With(x => x.CompanyId, companyId)
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();

var existingData = _fixture.Build<CompanyApplicationDetailData>()
Expand Down Expand Up @@ -1092,11 +1100,17 @@ public async Task SetCompanyWithAddressAsync_WithUniqueIdentifiers_CreateModifyD
var uniqueIdentifiers = _fixture.CreateMany<UniqueIdentifierId>(4);

var firstIdData = _fixture.Build<CompanyUniqueIdData>()
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.First()).Create(); // shall not modify
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.First())
.With(x => x.Value, "HRB123456")
.Create(); // shall not modify
var secondIdData = _fixture.Build<CompanyUniqueIdData>()
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.ElementAt(1)).Create(); // shall modify
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.ElementAt(1))
.With(x => x.Value, "DE124356789")
.Create(); // shall modify
var thirdIdData = _fixture.Build<CompanyUniqueIdData>()
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.ElementAt(2)).Create(); // shall create new
.With(x => x.UniqueIdentifierId, uniqueIdentifiers.ElementAt(2))
.With(x => x.Value, "54930084UKLVMY22DS16")
.Create(); // shall create new

var companyData = _fixture.Build<CompanyDetailData>()
.With(x => x.BusinessPartnerNumber, default(string?))
Expand Down Expand Up @@ -1184,6 +1198,7 @@ public async Task SetCompanyWithAddressAsync_WithInvalidCountryCode_Throws()
var companyData = _fixture.Build<CompanyDetailData>()
.With(x => x.BusinessPartnerNumber, default(string?))
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds, [new CompanyUniqueIdData(UniqueIdentifierId.VAT_ID, _vatId)])
.Create();
var identityData = A.Fake<IIdentityData>();
A.CallTo(() => identityData.IdentityId).Returns(Guid.NewGuid());
Expand Down Expand Up @@ -1231,7 +1246,10 @@ public async Task SetCompanyWithAddressAsync_WithInvalidUniqueIdentifiers_Throws
.With(x => x.CountryAlpha2Code, _alpha2code)
.With(x => x.UniqueIds,
identifiers.Select(id =>
_fixture.Build<CompanyUniqueIdData>().With(x => x.UniqueIdentifierId, id).Create()))
_fixture.Build<CompanyUniqueIdData>()
.With(x => x.UniqueIdentifierId, id)
.With(x => x.Value, _vatId)
.Create()))
.Create();

var sut = new RegistrationBusinessLogic(
Expand Down

0 comments on commit 460d738

Please sign in to comment.