コード例 #1
0
        public async Task ApplySecurityContractDefinitionAsync(SecurityContract securityContract, Guid updatedById, bool dryRun = false)
        {
            // Start transactions to allow complete rollback in case of an error
            BeginAllTransactions();

            try
            {
                SecurityContractDryRunResult securityContractDryRunResult = new SecurityContractDryRunResult();
                // First apply all of the application(micro-service) definitions that present within the Security Contract.
                // All the components of a security contract are optional, so check for this here.
                if (securityContract.Applications != null && securityContract.Applications.Count > 0)
                {
                    foreach (var applicationSecurityContractDefinition in securityContract.Applications)
                    {
                        await securityContractApplicationService.ApplyResourceServerDefinitionAsync(applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult);
                    }
                }

                // Apply any clients that may be defined within the security contract.
                if (securityContract.Clients != null && securityContract.Clients.Count > 0)
                {
                    foreach (var clientSecurityContractDefinition in securityContract.Clients)
                    {
                        await clientService.ApplyClientDefinitionAsync(clientSecurityContractDefinition, dryRun, securityContractDryRunResult);
                    }
                }

                // Apply any default configurations that may be defined within the security contract.
                if (securityContract.DefaultConfigurations != null && securityContract.DefaultConfigurations.Count > 0)
                {
                    foreach (var defaultConfiguration in securityContract.DefaultConfigurations)
                    {
                        await securityContractDefaultConfigurationService.ApplyDefaultConfigurationDefinitionAsync(defaultConfiguration, updatedById, dryRun, securityContractDryRunResult);
                    }
                }

                if (!dryRun)
                {
                    // All successful
                    CommitAllTransactions();
                }
                else
                {
                    var securityContractDryRunException = new SecurityContractDryRunException
                    {
                        ValidationErrors   = securityContractDryRunResult.ValidationErrors,
                        ValidationWarnings = securityContractDryRunResult.ValidationWarnings
                    };

                    throw securityContractDryRunException;
                }
            }
            catch
            {
                RollbackAllTransactions();
                throw;
            }
        }
コード例 #2
0
        public async Task <Oauth2Client> ApplyClientDefinitionAsync(Oauth2ClientSubmit oauth2ClientSubmit, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            logger.Debug($"[client.clientId: '{oauth2ClientSubmit.ClientId}']: Applying client definition for client: '{oauth2ClientSubmit.ClientId}'.");
            IdentityServer4.EntityFramework.Entities.Client client = await identityClientRepository.GetByClientIdAsync(oauth2ClientSubmit.ClientId);

            bool newClient = false;

            if (client == null)
            {
                client    = new IdentityServer4.EntityFramework.Entities.Client();
                newClient = true;
            }

            client.AllowOfflineAccess = oauth2ClientSubmit.AllowedOfflineAccess;
            client.ClientId           = oauth2ClientSubmit.ClientId;
            client.ClientName         = oauth2ClientSubmit.Name;

            // The following properties of clients are not externally configurable, but we do need to add them th clients to get the desired behaviour.
            client.UpdateAccessTokenClaimsOnRefresh = true;
            client.AlwaysSendClientClaims           = true;
            client.AlwaysIncludeUserClaimsInIdToken = true;
            client.RequireConsent = false;

            if (oauth2ClientSubmit.AccessTokenLifetime > 0)
            {
                client.AccessTokenLifetime = oauth2ClientSubmit.AccessTokenLifetime;
            }

            if (oauth2ClientSubmit.IdentityTokenLifetime > 0)
            {
                client.IdentityTokenLifetime = oauth2ClientSubmit.IdentityTokenLifetime;
            }

            client.RefreshTokenExpiration = (int)TokenExpiration.Absolute;
            client.RefreshTokenUsage      = (int)TokenUsage.OneTimeOnly;

            ApplyClientAllowedScopes(client, oauth2ClientSubmit);
            ApplyClientAllowedGrantTypes(client, oauth2ClientSubmit);
            ApplyClientSecrets(client, oauth2ClientSubmit);
            ApplyClientRedirectUris(client, oauth2ClientSubmit);
            ApplyClientPostLogoutRedirectUris(client, oauth2ClientSubmit);
            ApplyClientAllowedCorsOrigins(client, oauth2ClientSubmit, dryRun, securityContractDryRunResult);

            if (newClient)
            {
                logger.Debug($"[client.clientId: '{oauth2ClientSubmit.ClientId}']: Client '{oauth2ClientSubmit.ClientId}' does not exist. Creating it.");
                return(mapper.Map <Oauth2Client>(await identityClientRepository.CreateAsync(client)));
            }

            logger.Debug($"[client.clientId: '{oauth2ClientSubmit.ClientId}']: Client '{oauth2ClientSubmit.ClientId}' already exists. Updating it.");
            return(mapper.Map <Oauth2Client>(await identityClientRepository.UpdateAsync(client)));
        }
コード例 #3
0
        private void ApplyClientAllowedCorsOrigins(IdentityServer4.EntityFramework.Entities.Client client, Oauth2ClientSubmit oauth2ClientSubmit, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            client.AllowedCorsOrigins = new List <ClientCorsOrigin>();

            if (oauth2ClientSubmit.AllowedCorsOrigins != null && oauth2ClientSubmit.AllowedCorsOrigins.Any())
            {
                foreach (var corsOrigin in oauth2ClientSubmit.AllowedCorsOrigins)
                {
                    if (string.IsNullOrWhiteSpace(corsOrigin))
                    {
                        var errMessage = $"[client.clientId: '{oauth2ClientSubmit.ClientId}']: Empty or null 'allowedCorsOrigin' element declared for client: '{oauth2ClientSubmit.ClientId}'";

                        if (dryRun)
                        {
                            securityContractDryRunResult.ValidationErrors.Add(errMessage);
                        }
                        else
                        {
                            throw new InvalidFormatException(errMessage);
                        }
                    }

                    client.AllowedCorsOrigins.Add(new ClientCorsOrigin
                    {
                        Client = client,
                        Origin = corsOrigin
                    });
                }
            }
        }
コード例 #4
0
        private async Task <ApplicationModel> CreateApplication(SecurityContractApplication applicationSecurityContractDefinition, Guid updatedByGuid, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            await CreateApiResourceForApplicationOnIdentityServer(applicationSecurityContractDefinition);

            // Create the A3S representation of the resource.
            ApplicationModel application = new ApplicationModel
            {
                Name                    = applicationSecurityContractDefinition.Fullname,
                ChangedBy               = updatedByGuid,
                ApplicationFunctions    = new List <ApplicationFunctionModel>(),
                ApplicationDataPolicies = new List <ApplicationDataPolicyModel>()
            };

            if (applicationSecurityContractDefinition.ApplicationFunctions != null)
            {
                foreach (var function in applicationSecurityContractDefinition.ApplicationFunctions)
                {
                    // Application functions should be unique, check that another one does not exist prior to attempting to add it to the application.
                    var existingApplicationFunction = await applicationFunctionRepository.GetByNameAsync(function.Name);

                    if (existingApplicationFunction != null)
                    {
                        var errorMessage = $"[applications.fullname: '{applicationSecurityContractDefinition.Fullname}'].[applicationFunctions.name: '{function.Name}']: Cannot create application function '{function.Name}', as there is already an application function with this nam assigned to another application.";

                        if (dryRun)
                        {
                            securityContractDryRunResult.ValidationErrors.Add(errorMessage);
                            // Attempting to add the function anyway would result in a uniqueness contraint violation and break the transaction.
                            continue;
                        }

                        throw new ItemNotProcessableException(errorMessage);
                    }

                    logger.Error($"Adding function {function.Name} to application.");
                    application.ApplicationFunctions.Add(CreateNewApplicationFunctionFromSecurityContractApplicationFunction(function, updatedByGuid, applicationSecurityContractDefinition.Fullname, dryRun, securityContractDryRunResult));
                }
            }
            // Set an initial value to the un-saved model.
            ApplicationModel newApplication = await applicationRepository.CreateAsync(application);

            return(await SynchroniseApplicationDataPoliciesWithSecurityContract(newApplication, applicationSecurityContractDefinition, updatedByGuid, dryRun, securityContractDryRunResult));
        }
コード例 #5
0
        private void AssignExistingPermissionToApplicationFunction(PermissionModel existingPermission, string applicationName, ApplicationFunctionModel applicationFunction, SecurityContractPermission permission, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult, Guid updatedByGuid)
        {
            if (ExistingPermissionIsAssignedToAnotherApplication(existingPermission, applicationName))
            {
                var errorMessage = $"[applications.fullname: '{applicationName}'].[applicationFunctions.name: '{applicationFunction.Name}'].[permissions.name: '{permission.Name}']: Permission name exists, but is not assigned to application '{applicationName}'. Cannot assign it to application '{applicationName}', as permissions can only be assigned to a single application";
                if (dryRun)
                {
                    securityContractDryRunResult.ValidationErrors.Add(errorMessage);
                    return;
                }

                throw new ItemNotProcessableException(errorMessage);
            }

            logger.Debug($"[applications.fullname: '{applicationName}'].[applicationFunctions.name: '{applicationFunction.Name}'].[permissions.name: '{permission.Name}']: Permission '{permission.Name}' already assigned to application '{applicationName}'. Updating it.");
            var applicationFunctionPermission = applicationFunction.ApplicationFunctionPermissions.Find(fp => fp.Permission.Name == permission.Name);

            // This check will be true if the permission was assigned to another function attached to the same application. Prevent this!
            if (applicationFunctionPermission == null)
            {
                var errorMessage = $"[applications.fullname: '{applicationName}'].[applicationFunctions.name: '{applicationFunction.Name}'].[permissions.name: '{permission.Name}']: Permission '{permission.Name}' already assigned to another application function within application '{applicationName}'. This is prohibited.";
                if (dryRun)
                {
                    securityContractDryRunResult.ValidationErrors.Add(errorMessage);
                    return;
                }

                throw new ItemNotProcessableException(errorMessage);
            }

            // Still check if the permission is to be updated.
            if (applicationFunctionPermission.Permission.Description != permission.Description)
            {
                applicationFunctionPermission.Permission.Description = permission.Description;
                applicationFunctionPermission.Permission.ChangedBy   = updatedByGuid;
            }
        }
コード例 #6
0
        public async Task <ApplicationModel> ApplyResourceServerDefinitionAsync(SecurityContractApplication applicationSecurityContractDefinition, Guid updatedById, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            logger.Debug($"[applications.fullname: '{applicationSecurityContractDefinition.Fullname}']: Applying application security contract definition for application: '{applicationSecurityContractDefinition.Fullname}'");
            // Attempt to load any existing application by name, as the name is essentially the API primary key.
            var application = await applicationRepository.GetByNameAsync(applicationSecurityContractDefinition.Fullname);

            if (application == null)
            {
                logger.Debug($"[applications.fullname: '{applicationSecurityContractDefinition.Fullname}']: Application '{applicationSecurityContractDefinition.Fullname}' not found in database. Creating new application.");
                return(await CreateApplication(applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult));
            }

            logger.Debug($"[applications.fullname: '{applicationSecurityContractDefinition.Fullname}']: Application '{applicationSecurityContractDefinition.Fullname}' already exists. Updating it.");
            return(await UpdateExistingApplication(application, applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult));
        }
コード例 #7
0
        private ApplicationFunctionModel CreateNewApplicationFunctionFromSecurityContractApplicationFunction(SecurityContractFunction functionResource, Guid updatedByGuid, string applicationName, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            logger.Debug($"[applications.fullname: '{applicationName}'].[applicationFunctions.name: '{functionResource.Name}']: Adding function '{functionResource.Name}' to application '{applicationName}'.");
            ApplicationFunctionModel newFunction = new ApplicationFunctionModel
            {
                Name        = functionResource.Name,
                Description = functionResource.Description,
                ChangedBy   = updatedByGuid
            };

            newFunction.ApplicationFunctionPermissions = new List <ApplicationFunctionPermissionModel>();

            if (functionResource.Permissions != null)
            {
                foreach (var permission in functionResource.Permissions)
                {
                    AddSecurityContractPermissionToApplicationFunctionAndUpdatePermissionIfChanged(newFunction, permission, updatedByGuid, applicationName, dryRun, securityContractDryRunResult);
                }
            }

            return(newFunction);
        }
コード例 #8
0
        private void AddSecurityContractPermissionToApplicationFunctionAndUpdatePermissionIfChanged(ApplicationFunctionModel applicationFunction, SecurityContractPermission permission, Guid updatedByGuid, string applicationName, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            logger.Debug($"[applications.fullname: '{applicationName}'].[applicationFunctions.name: '{applicationFunction.Name}'].[permissions.name: '{permission.Name}']: Attempting to assign permission '{permission.Name}' to function: {applicationFunction.Name}.");
            // Check if there is an existing permission within the database. Add this one if found, but only if it is assigned to the current application, else create a new one and add it.
            var existingPermission = permissionRepository.GetByName(permission.Name, true);

            if (existingPermission != null)
            {
                AssignExistingPermissionToApplicationFunction(existingPermission, applicationName, applicationFunction, permission, dryRun, securityContractDryRunResult, updatedByGuid);
            }
            else
            {
                AssignNewPermissionToApplicationFunction(applicationName, applicationFunction, permission, updatedByGuid);
            }
        }
コード例 #9
0
        private async Task <ApplicationModel> SynchroniseFunctionsFromResourceServerDefinitionToApplication(ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedByGuid, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            if (applicationSecurityContractDefinition.ApplicationFunctions == null)
            {
                return(application);
            }

            foreach (var functionResource in applicationSecurityContractDefinition.ApplicationFunctions)
            {
                await SynchroniseSpecificFunctionFromResourceServerDefinitionToApplication(functionResource, application, applicationSecurityContractDefinition, updatedByGuid, dryRun, securityContractDryRunResult);
            }

            return(await applicationRepository.UpdateAsync(application));
        }
コード例 #10
0
        private async Task SynchroniseSpecificFunctionFromResourceServerDefinitionToApplication(SecurityContractFunction functionResource, ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedByGuid, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            var applicationFunction = application.ApplicationFunctions.Find(af => af.Name == functionResource.Name);

            if (applicationFunction == null)
            {
                logger.Debug($"[applications.fullname: '{application.Name}'].[applicationFunctions.name: '{functionResource.Name}']: Application function with name '{functionResource.Name}' does not exist. Creating it.");
                // We now know this application does not have a function with the name assigned. However, another one might, check for this.
                var existingApplicationFunction = await applicationFunctionRepository.GetByNameAsync(functionResource.Name);

                if (existingApplicationFunction != null)
                {
                    var errorMessage = $"[applications.fullname: '{application.Name}'].[applicationFunctions.name: '{functionResource.Name}']: Application function with name '{functionResource.Name}' already exists in another application. Cannot assign it to application: '{application.Name}'";
                    if (dryRun)
                    {
                        securityContractDryRunResult.ValidationErrors.Add(errorMessage);
                        return;
                    }

                    throw new ItemNotProcessableException(errorMessage);
                }

                application.ApplicationFunctions.Add(CreateNewApplicationFunctionFromSecurityContractApplicationFunction(functionResource, updatedByGuid, applicationSecurityContractDefinition.Fullname, dryRun, securityContractDryRunResult));
            }
            else
            {
                logger.Debug($"[applications.fullname: '{application.Name}'].[applicationFunctions.name: '{functionResource.Name}']: Application function with name '{functionResource.Name}' already exists. Updating it.");
                // Edit an existing function.
                applicationFunction.Name        = functionResource.Name;
                applicationFunction.Description = functionResource.Description;
                applicationFunction.ChangedBy   = updatedByGuid;

                if (functionResource.Permissions != null)
                {
                    DetectAndUnassignPermissionsRemovedFromFunctions(applicationFunction, functionResource);

                    // Add any new permissions to the function.
                    foreach (var permission in functionResource.Permissions)
                    {
                        AddSecurityContractPermissionToApplicationFunctionAndUpdatePermissionIfChanged(applicationFunction, permission, updatedByGuid, applicationSecurityContractDefinition.Fullname, dryRun, securityContractDryRunResult);
                    }
                }
                else
                {
                    // Remove any possible permissions that are assigned to the application function.
                    applicationFunction.ApplicationFunctionPermissions.Clear();
                }
            }
        }
コード例 #11
0
        private async Task <ApplicationModel> SynchroniseFunctions(ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedByGuid, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            await DetectApplicationFunctionsRemovedFromSecurityContractAndRemoveFromApplication(application, applicationSecurityContractDefinition);

            await permissionRepository.DeletePermissionsNotAssignedToApplicationFunctionsAsync();

            await SynchroniseFunctionsFromResourceServerDefinitionToApplication(application, applicationSecurityContractDefinition, updatedByGuid, dryRun, securityContractDryRunResult);

            return(application);
        }
コード例 #12
0
        private async Task <ApplicationModel> UpdateExistingApplication(ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedById, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            var updatedApplication = await SynchroniseFunctions(application, applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult);

            await SynchroniseApplicationDataPoliciesWithSecurityContract(application, applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult);

            return(updatedApplication);
        }
コード例 #13
0
        private async Task AddSpecificApplicationDataPolyFromSecurityContractToApplication(ApplicationModel application, SecurityContractApplicationDataPolicy dataPolicyToAdd, Guid updatedById, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            logger.Debug($"[applications.fullname: '{application.Name}'].[dataPolicies.name: '{dataPolicyToAdd.Name}']: Adding data policy '{dataPolicyToAdd.Name}' to application '{application.Name}'.");
            var existingDataPolicy = application.ApplicationDataPolicies.Find(adp => adp.Name == dataPolicyToAdd.Name);

            if (existingDataPolicy == null)
            {
                //check that the data policy does not exist within other applications.
                var dataPolicyAttachedToOtherApplication = await applicationDataPolicyRepository.GetByNameAsync(dataPolicyToAdd.Name);

                if (dataPolicyAttachedToOtherApplication != null)
                {
                    var errorMessage = $"[applications.fullname: '{application.Name}'].[dataPolicies.name: '{dataPolicyToAdd.Name}']: Data policy with name alreay exists in another application. Not adding it!";
                    if (dryRun)
                    {
                        securityContractDryRunResult.ValidationErrors.Add(errorMessage);
                        return;
                    }

                    throw new ItemNotProcessableException(errorMessage);
                }

                logger.Debug($"[applications.fullname: '{application.Name}'].[dataPolicies.name: '{dataPolicyToAdd.Name}']: Data policy '{dataPolicyToAdd.Name}' was not assigned to application '{application.Name}'. Adding it.");
                application.ApplicationDataPolicies.Add(new ApplicationDataPolicyModel
                {
                    Name        = dataPolicyToAdd.Name,
                    Description = dataPolicyToAdd.Description,
                    ChangedBy   = updatedById
                });
            }
            else
            {
                logger.Debug($"[applications.fullname: '{application.Name}'].[dataPolicies.name: '{dataPolicyToAdd.Name}']: Data policy '{dataPolicyToAdd.Name}' is currently assigned to application '{application.Name}'. Updating it.");
                // Bind possible changes to the editable components of the data policy.
                existingDataPolicy.Description = dataPolicyToAdd.Description;
                existingDataPolicy.ChangedBy   = updatedById;
            }
        }
コード例 #14
0
        private async Task <ApplicationModel> AddApplicationDataPoliciesFromSecurityContractToApplication(ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedById, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            if (applicationSecurityContractDefinition.DataPolicies != null && applicationSecurityContractDefinition.DataPolicies.Any())
            {
                foreach (var dataPolicyToAdd in applicationSecurityContractDefinition.DataPolicies)
                {
                    await AddSpecificApplicationDataPolyFromSecurityContractToApplication(application, dataPolicyToAdd, updatedById, dryRun, securityContractDryRunResult);
                }
            }
            else
            {
                logger.Debug($"[applications.fullname: '{application.Name}'].[dataPolicies]: No application data policies defined for application '{application.Name}'.");
            }

            return(await applicationRepository.UpdateAsync(application));
        }
コード例 #15
0
        private async Task <ApplicationModel> SynchroniseApplicationDataPoliciesWithSecurityContract(ApplicationModel application, SecurityContractApplication applicationSecurityContractDefinition, Guid updatedById, bool dryRun, SecurityContractDryRunResult securityContractDryRunResult)
        {
            await RemoveApplicationDataPoliciesCurrentlyAssignedToApplicationThatAreNoLongerInSecurityContract(application, applicationSecurityContractDefinition);

            return(await AddApplicationDataPoliciesFromSecurityContractToApplication(application, applicationSecurityContractDefinition, updatedById, dryRun, securityContractDryRunResult));
        }