/// <inheritdoc/> public async Task <DelegationChange> InsertDelegation(DelegationChange delegationChange) { try { await using NpgsqlConnection conn = new NpgsqlConnection(_connectionString); await conn.OpenAsync(); NpgsqlCommand pgcom = new NpgsqlCommand(insertDelegationChangeFunc, conn); pgcom.Parameters.AddWithValue("_delegationChangeType", delegationChange.DelegationChangeType); pgcom.Parameters.AddWithValue("_altinnAppId", delegationChange.AltinnAppId); pgcom.Parameters.AddWithValue("_offeredByPartyId", delegationChange.OfferedByPartyId); pgcom.Parameters.AddWithValue("_coveredByUserId", delegationChange.CoveredByUserId.HasValue ? delegationChange.CoveredByUserId.Value : DBNull.Value); pgcom.Parameters.AddWithValue("_coveredByPartyId", delegationChange.CoveredByPartyId.HasValue ? delegationChange.CoveredByPartyId.Value : DBNull.Value); pgcom.Parameters.AddWithValue("_performedByUserId", delegationChange.PerformedByUserId); pgcom.Parameters.AddWithValue("_blobStoragePolicyPath", delegationChange.BlobStoragePolicyPath); pgcom.Parameters.AddWithValue("_blobStorageVersionId", delegationChange.BlobStorageVersionId); using NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync(); if (reader.Read()) { return(GetDelegationChange(reader)); } return(null); } catch (Exception e) { _logger.LogError(e, "Authorization // DelegationMetadataRepository // Insert // Exception"); throw; } }
private static DelegationChangeEventList GetDelegationChangeList() { return(new DelegationChangeEventList { DelegationChangeEvents = new List <DelegationChangeEvent> { new() { EventType = DelegationChangeEventType.Grant, DelegationChange = new DelegationChange { DelegationChangeId = 1, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByPartyId = 234, PerformedByUserId = 567, Created = DateTime.UtcNow } }, new() { EventType = DelegationChangeEventType.Revoke, DelegationChange = new DelegationChange { DelegationChangeId = 2, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByPartyId = 234, PerformedByUserId = 567, Created = DateTime.UtcNow } }, new() { EventType = DelegationChangeEventType.Grant, DelegationChange = new DelegationChange { DelegationChangeId = 3, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByUserId = 345, PerformedByUserId = 567, Created = DateTime.UtcNow } }, new() { EventType = DelegationChangeEventType.RevokeLast, DelegationChange = new DelegationChange { DelegationChangeId = 4, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByUserId = 345, PerformedByUserId = 567, Created = DateTime.UtcNow } } } });
/// <summary> /// Converts the delegation change to a delegation change event and pushes it to the event queue. /// Throws exception if something fails /// </summary> /// <param name="delegationChange">The delegation change stored in postgresql</param> public async Task <SendReceipt> Push(DelegationChange delegationChange) { DelegationChangeEventList dceList = _eventMapperService.MapToDelegationChangeEventList(new List <DelegationChange> { delegationChange }); QueueClient queueClient = await GetQueueClient(); return(await queueClient.SendMessageAsync(JsonSerializer.Serialize(dceList))); }
/// <summary> /// Mocks pushing delegation changes to the event queue /// </summary> /// <param name="delegationChange">The delegation change stored in postgresql</param> public Task <SendReceipt> Push(DelegationChange delegationChange) { if (string.IsNullOrEmpty(delegationChange.AltinnAppId) || delegationChange.AltinnAppId == "error/delegationeventfail") { throw new Exception("DelegationChangeEventQueue || Push || Error"); } return(Task.FromResult((SendReceipt)null)); }
public void MapEventWithCoveredByUser() { // Arrange EventMapperService service = new(); DateTime now = DateTime.Now; DelegationChangeEventList input = new() { DelegationChangeEvents = new List <DelegationChangeEvent> { new() { EventType = DelegationChangeEventType.Grant, DelegationChange = new DelegationChange { DelegationChangeId = 1, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByUserId = 234, PerformedByUserId = 567, Created = now } } } }; List <PlatformDelegationEvent> expectedOutput = new List <PlatformDelegationEvent>() { new() { PolicyChangeId = 1, EventType = DelegationChangeEventType.Grant, AltinnAppId = "ttd/testapp", OfferedByPartyId = 123, CoveredByPartyId = 0, CoveredByUserId = 234, PerformedByUserId = 567, Created = now } }; // Act List <PlatformDelegationEvent> output = service.MapToPlatformEventList(input); // Assert expectedOutput.Should().BeEquivalentTo(output); } }
public static void AssertEqual(List <DelegationChange> expected, List <DelegationChange> actual) { if (expected == null) { Assert.Null(actual); return; } Assert.Equal(expected.Count, actual.Count); foreach (DelegationChange expectedEntity in expected) { DelegationChange actualentity = actual.FirstOrDefault(a => a.AltinnAppId == expectedEntity.AltinnAppId && a.BlobStoragePolicyPath == expectedEntity.BlobStoragePolicyPath && a.CoveredByPartyId == expectedEntity.CoveredByPartyId && a.CoveredByUserId == expectedEntity.CoveredByUserId && a.OfferedByPartyId == expectedEntity.OfferedByPartyId && a.DelegationChangeType == expectedEntity.DelegationChangeType); Assert.NotNull(actualentity); } }
public Task <DelegationChange> InsertDelegation(DelegationChange delegationChange) { List <DelegationChange> current; string coveredBy = delegationChange.CoveredByPartyId != null ? $"p{delegationChange.CoveredByPartyId}" : $"u{delegationChange.CoveredByUserId}"; string key = $"{delegationChange.AltinnAppId}/{delegationChange.OfferedByPartyId}/{coveredBy}"; if (MetadataChanges.ContainsKey(key)) { current = MetadataChanges[key]; } else { current = new List <DelegationChange>(); MetadataChanges[key] = current; } DelegationChange currentDelegationChange = new DelegationChange { DelegationChangeId = 1337, DelegationChangeType = delegationChange.DelegationChangeType, AltinnAppId = delegationChange.AltinnAppId, OfferedByPartyId = delegationChange.OfferedByPartyId, CoveredByPartyId = delegationChange.CoveredByPartyId, CoveredByUserId = delegationChange.CoveredByUserId, PerformedByUserId = delegationChange.PerformedByUserId, BlobStoragePolicyPath = delegationChange.BlobStoragePolicyPath, BlobStorageVersionId = delegationChange.BlobStorageVersionId, Created = DateTime.Now }; current.Add(currentDelegationChange); if (string.IsNullOrEmpty(delegationChange.AltinnAppId) || delegationChange.AltinnAppId == "error/postgrewritechangefail") { currentDelegationChange.DelegationChangeId = 0; return(Task.FromResult(currentDelegationChange)); } return(Task.FromResult(currentDelegationChange)); }
private async Task <List <Rule> > DeleteAllRulesInPolicy(RequestToDelete policyToDelete) { DelegationHelper.TryGetResourceFromAttributeMatch(policyToDelete.PolicyMatch.Resource, out string org, out string app); string coveredBy = DelegationHelper.GetCoveredByFromMatch(policyToDelete.PolicyMatch.CoveredBy, out int?coveredByUserId, out int?coveredByPartyId); string policyPath; try { policyPath = PolicyHelper.GetAltinnAppDelegationPolicyPath(org, app, policyToDelete.PolicyMatch.OfferedByPartyId.ToString(), coveredByUserId, coveredByPartyId); } catch (Exception ex) { _logger.LogError(ex, "Not possible to build policy path App: {org}/{app} CoveredBy: {coveredBy} OfferedBy: {policyToDelete.PolicyMatch.OfferedByPartyId}", org, app, coveredBy, policyToDelete.PolicyMatch.OfferedByPartyId); return(null); } if (!await _policyRepository.PolicyExistsAsync(policyPath)) { _logger.LogWarning("No blob was found for the expected path: {policyPath} this must be removed without upading the database", policyPath); return(null); } string leaseId = await _policyRepository.TryAcquireBlobLease(policyPath); if (leaseId == null) { _logger.LogError("Could not acquire blob lease on delegation policy at path: {policyPath}", policyPath); return(null); } try { DelegationChange currentChange = await _delegationRepository.GetCurrentDelegationChange($"{org}/{app}", policyToDelete.PolicyMatch.OfferedByPartyId, coveredByPartyId, coveredByUserId); if (currentChange.DelegationChangeType == DelegationChangeType.RevokeLast) { _logger.LogWarning("The policy is already deleted for App: {org}/{app} CoveredBy: {coveredBy} OfferedBy: {policyToDelete.PolicyMatch.OfferedByPartyId}", org, app, coveredBy, policyToDelete.PolicyMatch.OfferedByPartyId); return(null); } XacmlPolicy existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId); List <Rule> currentPolicyRules = new List <Rule>(); foreach (XacmlRule xacmlRule in existingDelegationPolicy.Rules) { currentPolicyRules.Add(PolicyHelper.CreateRuleFromPolicyAndRuleMatch(policyToDelete, xacmlRule)); } existingDelegationPolicy.Rules.Clear(); Response <BlobContentInfo> response; try { MemoryStream dataStream = PolicyHelper.GetXmlMemoryStreamFromXacmlPolicy(existingDelegationPolicy); response = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); } catch (Exception ex) { _logger.LogError(ex, "Writing of delegation policy at path: {policyPath} failed. Is delegation blob storage account alive and well?}", policyPath); return(null); } DelegationChange change = new DelegationChange { DelegationChangeType = DelegationChangeType.RevokeLast, AltinnAppId = $"{org}/{app}", OfferedByPartyId = policyToDelete.PolicyMatch.OfferedByPartyId, CoveredByPartyId = coveredByPartyId, CoveredByUserId = coveredByUserId, PerformedByUserId = policyToDelete.DeletedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = response.Value.VersionId }; change = await _delegationRepository.InsertDelegation(change); if (change == null || change.DelegationChangeId <= 0) { // Comment: // This means that the current version of the root blob is no longer in sync with changes in authorization postgresql delegation.delegatedpolicy table. // The root blob is in effect orphaned/ignored as the delegation policies are always to be read by version, and will be overritten by the next delegation change. _logger.LogError("Writing of delegation change to authorization postgresql database failed for changes to delegation policy at path: {policyPath}. is authorization postgresql database alive and well?", policyPath); return(null); } try { await _eventQueue.Push(change); } catch (Exception ex) { _logger.LogCritical(new EventId(delegationChangeEventQueueErrorId, "DelegationChangeEventQueue.Push.Error"), ex, "DeletePolicy could not push DelegationChangeEvent to DelegationChangeEventQueue. DelegationChangeEvent must be retried for successful sync with SBL Authorization. DelegationChange: {change}", change); } return(currentPolicyRules); } catch (Exception ex) { _logger.LogError(ex, "An exception occured while processing rules to delete in policy: {policyPath}", policyPath); return(null); } finally { _policyRepository.ReleaseBlobLease(policyPath, leaseId); } }
private async Task <List <Rule> > ProcessPolicyFile(string policyPath, string org, string app, RequestToDelete deleteRequest) { List <Rule> currentRules = new List <Rule>(); string leaseId = await _policyRepository.TryAcquireBlobLease(policyPath); if (leaseId == null) { _logger.LogError("Could not acquire blob lease lock on delegation policy at path: {policyPath}", policyPath); return(null); } try { bool isAllRulesDeleted = false; string coveredBy = DelegationHelper.GetCoveredByFromMatch(deleteRequest.PolicyMatch.CoveredBy, out int?coveredByUserId, out int?coveredByPartyId); string offeredBy = deleteRequest.PolicyMatch.OfferedByPartyId.ToString(); DelegationChange currentChange = await _delegationRepository.GetCurrentDelegationChange($"{org}/{app}", deleteRequest.PolicyMatch.OfferedByPartyId, coveredByPartyId, coveredByUserId); XacmlPolicy existingDelegationPolicy = null; if (currentChange.DelegationChangeType == DelegationChangeType.RevokeLast) { _logger.LogWarning("The policy is already deleted for App: {org}/{app} CoveredBy: {coveredBy} OfferedBy: {offeredBy}", org, app, coveredBy, offeredBy); return(null); } existingDelegationPolicy = await _prp.GetPolicyVersionAsync(currentChange.BlobStoragePolicyPath, currentChange.BlobStorageVersionId); foreach (string ruleId in deleteRequest.RuleIds) { XacmlRule xacmlRuleToRemove = existingDelegationPolicy.Rules.FirstOrDefault(r => r.RuleId == ruleId); if (xacmlRuleToRemove == null) { _logger.LogWarning("The rule with id: {ruleId} does not exist in policy with path: {policyPath}", ruleId, policyPath); continue; } existingDelegationPolicy.Rules.Remove(xacmlRuleToRemove); Rule currentRule = PolicyHelper.CreateRuleFromPolicyAndRuleMatch(deleteRequest, xacmlRuleToRemove); currentRules.Add(currentRule); } isAllRulesDeleted = existingDelegationPolicy.Rules.Count == 0; // if nothing is deleted no update has been done and policy and postgree update can be skipped if (currentRules.Count > 0) { Response <BlobContentInfo> response; try { // Write delegation policy to blob storage MemoryStream dataStream = PolicyHelper.GetXmlMemoryStreamFromXacmlPolicy(existingDelegationPolicy); response = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); } catch (Exception ex) { _logger.LogError(ex, "Writing of delegation policy at path: {policyPath} failed. Is delegation blob storage account alive and well?", policyPath); return(null); } // Write delegation change to postgresql DelegationChange change = new DelegationChange { DelegationChangeType = isAllRulesDeleted ? DelegationChangeType.RevokeLast : DelegationChangeType.Revoke, AltinnAppId = $"{org}/{app}", OfferedByPartyId = deleteRequest.PolicyMatch.OfferedByPartyId, CoveredByPartyId = coveredByPartyId, CoveredByUserId = coveredByUserId, PerformedByUserId = deleteRequest.DeletedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = response.Value.VersionId }; change = await _delegationRepository.InsertDelegation(change); if (change == null || change.DelegationChangeId <= 0) { // Comment: // This means that the current version of the root blob is no longer in sync with changes in authorization postgresql delegation.delegatedpolicy table. // The root blob is in effect orphaned/ignored as the delegation policies are always to be read by version, and will be overritten by the next delegation change. _logger.LogError("Writing of delegation change to authorization postgresql database failed for changes to delegation policy at path: {policyPath}. is authorization postgresql database alive and well?", policyPath); return(null); } try { await _eventQueue.Push(change); } catch (Exception ex) { _logger.LogCritical(new EventId(delegationChangeEventQueueErrorId, "DelegationChangeEventQueue.Push.Error"), ex, "DeleteRules could not push DelegationChangeEvent to DelegationChangeEventQueue. DelegationChangeEvent must be retried for successful sync with SBL Authorization. DelegationChange: {change}", change); } } } catch (Exception ex) { _logger.LogError(ex, "An exception occured while processing rules to delete in policy: {policyPath}", policyPath); return(null); } finally { _policyRepository.ReleaseBlobLease(policyPath, leaseId); } return(currentRules); }
private async Task <bool> WriteDelegationPolicyInternal(string policyPath, List <Rule> rules) { if (!DelegationHelper.TryGetDelegationParamsFromRule(rules.First(), out string org, out string app, out int offeredByPartyId, out int?coveredByPartyId, out int?coveredByUserId, out int delegatedByUserId)) { _logger.LogWarning("This should not happen. Incomplete rule model received for delegation to delegation policy at: {policyPath}. Incomplete model should have been returned in unsortable rule set by TryWriteDelegationPolicyRules. DelegationHelper.SortRulesByDelegationPolicyPath might be broken.", policyPath); return(false); } XacmlPolicy appPolicy = await _prp.GetPolicyAsync(org, app); if (appPolicy == null) { _logger.LogWarning("No valid App policy found for delegation policy path: {policyPath}", policyPath); return(false); } foreach (Rule rule in rules) { if (!DelegationHelper.PolicyContainsMatchingRule(appPolicy, rule)) { _logger.LogWarning("Matching rule not found in app policy. Action might not exist for Resource, or Resource itself might not exist. Delegation policy path: {policyPath}. Rule: {rule}", policyPath, rule); return(false); } } if (!await _policyRepository.PolicyExistsAsync(policyPath)) { // Create a new empty blob for lease locking await _policyRepository.WritePolicyAsync(policyPath, new MemoryStream()); } string leaseId = await _policyRepository.TryAcquireBlobLease(policyPath); if (leaseId != null) { try { // Check for a current delegation change from postgresql DelegationChange currentChange = await _delegationRepository.GetCurrentDelegationChange($"{org}/{app}", offeredByPartyId, coveredByPartyId, coveredByUserId); XacmlPolicy existingDelegationPolicy = null; if (currentChange != null && currentChange.DelegationChangeType != DelegationChangeType.RevokeLast) { existingDelegationPolicy = await _prp.GetPolicyVersionAsync(policyPath, currentChange.BlobStorageVersionId); } // Build delegation XacmlPolicy either as a new policy or add rules to existing XacmlPolicy delegationPolicy; if (existingDelegationPolicy != null) { delegationPolicy = existingDelegationPolicy; foreach (Rule rule in rules) { if (!DelegationHelper.PolicyContainsMatchingRule(delegationPolicy, rule)) { delegationPolicy.Rules.Add(PolicyHelper.BuildDelegationRule(org, app, offeredByPartyId, coveredByPartyId, coveredByUserId, rule)); } } } else { delegationPolicy = PolicyHelper.BuildDelegationPolicy(org, app, offeredByPartyId, coveredByPartyId, coveredByUserId, rules); } // Write delegation policy to blob storage MemoryStream dataStream = PolicyHelper.GetXmlMemoryStreamFromXacmlPolicy(delegationPolicy); Response <BlobContentInfo> blobResponse = await _policyRepository.WritePolicyConditionallyAsync(policyPath, dataStream, leaseId); Response httpResponse = blobResponse.GetRawResponse(); if (httpResponse.Status != (int)HttpStatusCode.Created) { _logger.LogError("Writing of delegation policy at path: {policyPath} failed. Response Status Code:\n{httpResponse.Status}. Response Reason Phrase:\n{httpResponse.ReasonPhrase}", policyPath, httpResponse.Status, httpResponse.ReasonPhrase); return(false); } // Write delegation change to postgresql DelegationChange change = new DelegationChange { DelegationChangeType = DelegationChangeType.Grant, AltinnAppId = $"{org}/{app}", OfferedByPartyId = offeredByPartyId, CoveredByPartyId = coveredByPartyId, CoveredByUserId = coveredByUserId, PerformedByUserId = delegatedByUserId, BlobStoragePolicyPath = policyPath, BlobStorageVersionId = blobResponse.Value.VersionId }; change = await _delegationRepository.InsertDelegation(change); if (change == null || change.DelegationChangeId <= 0) { // Comment: // This means that the current version of the root blob is no longer in sync with changes in authorization postgresql delegation.delegatedpolicy table. // The root blob is in effect orphaned/ignored as the delegation policies are always to be read by version, and will be overritten by the next delegation change. _logger.LogError("Writing of delegation change to authorization postgresql database failed for changes to delegation policy at path: {policyPath}", policyPath); return(false); } try { await _eventQueue.Push(change); } catch (Exception ex) { _logger.LogCritical(new EventId(delegationChangeEventQueueErrorId, "DelegationChangeEventQueue.Push.Error"), ex, "AddRules could not push DelegationChangeEvent to DelegationChangeEventQueue. DelegationChangeEvent must be retried for successful sync with SBL Authorization. DelegationChange: {change}", change); } return(true); } finally { _policyRepository.ReleaseBlobLease(policyPath, leaseId); } } _logger.LogInformation("Could not acquire blob lease lock on delegation policy at path: {policyPath}", policyPath); return(false); }
private static List <Rule> GetRulesFromPolicyAndDelegationChange(ICollection <XacmlRule> xacmlRules, DelegationChange delegationChange) { List <Rule> rules = new List <Rule>(); foreach (XacmlRule xacmlRule in xacmlRules) { if (xacmlRule.Effect.Equals(XacmlEffectType.Permit) && xacmlRule.Target != null) { Rule rule = new Rule { RuleId = xacmlRule.RuleId, OfferedByPartyId = delegationChange.OfferedByPartyId, DelegatedByUserId = delegationChange.PerformedByUserId, CoveredBy = new List <AttributeMatch>(), Resource = new List <AttributeMatch>() }; AddAttributeMatchesToRule(xacmlRule.Target, rule); rules.Add(rule); } } return(rules); }
public Task <List <DelegationChange> > GetAllCurrentDelegationChanges(List <int> offeredByPartyIds, List <string> altinnAppIds, List <int> coveredByPartyIds, List <int> coveredByUserIds) { List <DelegationChange> result = new List <DelegationChange>(); if (altinnAppIds.Any(appId => appId == "org1/app1") && offeredByPartyIds.Contains(50001337) && (coveredByUserIds != null && coveredByUserIds.Contains(20001337))) { result.Add(TestDataHelper.GetDelegationChange("org1/app1", 50001337, coveredByUserId: 20001337)); } if (altinnAppIds.Any(appId => appId == "skd/taxreport") && offeredByPartyIds.Contains(1000) && (coveredByUserIds != null && coveredByUserIds.Contains(20001337))) { result.Add(TestDataHelper.GetDelegationChange("skd/taxreport", 1000, coveredByUserId: 20001337)); } if (altinnAppIds.Any(appId => appId == "org1/app1") && offeredByPartyIds.Contains(50001337) && (coveredByUserIds != null && coveredByUserIds.Contains(20001338))) { DelegationChange delegation = TestDataHelper.GetDelegationChange("org1/app1", 50001337, coveredByUserId: 20001338); delegation.DelegationChangeType = DelegationChangeType.RevokeLast; result.Add(delegation); } if (altinnAppIds.Any(appId => appId == "org1/app1") && offeredByPartyIds.Contains(50001337) && (coveredByPartyIds != null && coveredByPartyIds.Contains(50001336))) { result.Add(TestDataHelper.GetDelegationChange("org1/app1", 50001337, coveredByPartyId: 50001336)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001337) && (coveredByUserIds != null && coveredByUserIds.Contains(20001336))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001337, coveredByUserId: 20001336, performedByUserId: 20001337, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001337) && (coveredByUserIds != null && coveredByUserIds.Contains(20001335))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001337, coveredByPartyId: 50001335, performedByUserId: 20001337, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001337) && (coveredByPartyIds != null && coveredByPartyIds.Contains(50001336))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001337, coveredByPartyId: 50001338, performedByUserId: 20001337, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001338) && (coveredByPartyIds != null && coveredByPartyIds.Contains(50001339))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001338, coveredByPartyId: 50001339, performedByUserId: 20001338, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001338) && (coveredByPartyIds != null && coveredByPartyIds.Contains(50001340))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001338, coveredByPartyId: 50001340, performedByUserId: 20001338, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001338) && (coveredByPartyIds != null && coveredByPartyIds.Contains(50001336))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001338, coveredByPartyId: 50001336, performedByUserId: 20001339, changeType: DelegationChangeType.Grant)); } if (altinnAppIds.Contains("SKD/TaxReport") && offeredByPartyIds.Contains(50001339) && (coveredByPartyIds != null && coveredByUserIds.Contains(20001336))) { result.Add(TestDataHelper.GetDelegationChange("SKD/TaxReport", 50001335, coveredByPartyId: 50001337, performedByUserId: 20001339, changeType: DelegationChangeType.Grant)); } return(Task.FromResult(result)); }