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); }