Example #1
0
 /// <inheritdoc />
 public Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > CheckAccessPoliciesAsync(
     IOpenApiContext context,
     params AccessCheckOperationDescriptor[] requests)
 {
     return(OpenApiAccessPolicyAggregator.EvaluteAccessPoliciesConcurrentlyAsync(
                this.accessControlPolicies, context, requests));
 }
Example #2
0
        public async Task <OpenApiResult> GetClaimPermissionResourceAccessRulesAsync(
            IOpenApiContext context,
            string claimPermissionsId)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (claimPermissionsId is null)
            {
                throw new ArgumentNullException(nameof(claimPermissionsId));
            }

            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId).ConfigureAwait(false);

            IClaimPermissionsStore store = await this.permissionsStoreFactory.GetClaimPermissionsStoreAsync(tenant).ConfigureAwait(false);

            try
            {
                ClaimPermissions claimPermissions = await store.GetAsync(claimPermissionsId).ConfigureAwait(false);

                return(this.OkResult(claimPermissions.AllResourceAccessRules, "application/json"));
            }
            catch (ClaimPermissionsNotFoundException)
            {
                return(this.NotFoundResult());
            }
        }
        public async Task <OpenApiResult> GetNotificationsForUserAsync(
            IOpenApiContext context,
            string userId,
            string?sinceNotificationId,
            int?maxItems,
            string?continuationToken)
        {
            // We can guarantee tenant Id is available because it's part of the Uri.
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            IUserNotificationStore userNotificationStore =
                await this.userNotificationStoreFactory.GetUserNotificationStoreForTenantAsync(tenant).ConfigureAwait(false);

            maxItems ??= 50;

            GetNotificationsResult results = await this.GetNotificationsAsync(
                userId,
                sinceNotificationId,
                maxItems.Value,
                continuationToken,
                userNotificationStore).ConfigureAwait(false);

            await this.EnsureAllNotificationsMarkedAsDelivered(context, results).ConfigureAwait(false);

            HalDocument result = await this.userNotificationsMapper.MapAsync(
                results,
                new UserNotificationsMappingContext(context, userId, sinceNotificationId, maxItems.Value, continuationToken)).ConfigureAwait(false);

            return(this.OkResult(result));
        }
Example #4
0
        /// <inheritdoc />
        public Task LogAsync(IOpenApiContext context, AuditLog log)
        {
            string data = JsonConvert.SerializeObject(log, Formatting.Indented, this.openApiConfiguration.SerializerSettings);

            Console.WriteLine(data);
            return(Task.CompletedTask);
        }
 public ShouldAllowArgs(
     AccessCheckOperationDescriptor[] requests,
     IOpenApiContext context)
 {
     this.Requests = requests;
     this.Context  = context;
 }
        public async Task <OpenApiResult> GenerateTemplateAsync(
            IOpenApiContext context,
            CreateNotificationsRequest body)
        {
            // We can guarantee tenant Id is available because it's part of the Uri.
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            var registeredCommunicationChannels = new List <CommunicationType>()
            {
                CommunicationType.WebPush, CommunicationType.Email, CommunicationType.Sms
            };

            // TODO: In the future, check if these registeredCommunicationChannels are actually usable for the current Tenant.
            if (registeredCommunicationChannels is null || registeredCommunicationChannels.Count == 0)
            {
                throw new Exception($"There are no communication channel set up for the user {body.UserIds[0]} for notification type {body.NotificationType} for tenant {tenant.Id}");
            }

            // Gets the AzureBlobTemplateStore
            INotificationTemplateStore templateStore = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false);

            NotificationTemplate?responseTemplate = await this.generateTemplateComposer.GenerateTemplateAsync(templateStore, body.Properties, registeredCommunicationChannels, body.NotificationType).ConfigureAwait(false);

            return(this.OkResult(responseTemplate));
        }
Example #7
0
        /// <summary>
        /// Build an audit log for a given result, operation, and context.
        /// </summary>
        /// <param name="context">The OpenAPI context.</param>
        /// <param name="result">The result of the operation.</param>
        /// <param name="operation">The OpenAPI operation.</param>
        /// <returns>The audit log entry for the result, operation, and context.</returns>
        private AuditLog?BuildAuditLog(IOpenApiContext context, object result, OpenApiOperation operation)
        {
            if (this.logger.IsEnabled(LogLevel.Debug))
            {
                this.logger.LogDebug(
                    "Building audit log for [{operation}]",
                    operation.OperationId);
            }

            foreach (IAuditLogBuilder auditLogBuilder in this.auditLogBuilders)
            {
                if (auditLogBuilder.CanBuildAuditLog(context, result, operation))
                {
                    return(auditLogBuilder.BuildAuditLog(context, result, operation));
                }
            }

            if (this.logger.IsEnabled(LogLevel.Warning))
            {
                this.logger.LogWarning(
                    "Unable to build audit log for [{operation}]",
                    operation.OperationId);
            }

            return(null);
        }
        /// <inheritdoc/>
        public async Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > ShouldAllowAsync(
            IOpenApiContext context,
            params AccessCheckOperationDescriptor[] requests)
        {
            IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> firstPolicyResults = await this.firstPolicy.ShouldAllowAsync(context, requests).ConfigureAwait(false);

            // Get the "denys" from the first policy results so we can feed them into the second.
            AccessCheckOperationDescriptor[] deniedByFirstPolicy = firstPolicyResults.Where(x => !x.Value.Allow).Select(x => x.Key).ToArray();

            // If there weren't any denies from the first policy, then we can return immediately as
            // there's no further work to do.
            if (deniedByFirstPolicy.Length == 0)
            {
                return(firstPolicyResults);
            }

            // Evaluate the remaining requests.
            IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> otherPolicyResults = await OpenApiAccessPolicyAggregator.EvaluteAccessPoliciesConcurrentlyAsync(
                this.otherPolicies,
                context,
                deniedByFirstPolicy).ConfigureAwait(false);

            // Merge the result from the other policies into that from the first.
            otherPolicyResults.ForEach(x => firstPolicyResults[x.Key] = x.Value);
            return(firstPolicyResults);
        }
        public async Task <OpenApiResult> CreateNotificationsAsync(
            IOpenApiContext context,
            CreateNotificationsRequest body)
        {
            // We can guarantee tenant Id is available because it's part of the Uri.
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            string delegatedTenantId = await this.marainServicesTenancy.GetDelegatedTenantIdForRequestingTenantAsync(tenant.Id).ConfigureAwait(false);

            var operationId = Guid.NewGuid();
            CreateOperationHeaders response = await this.operationsControlClient.CreateOperationAsync(
                delegatedTenantId,
                operationId).ConfigureAwait(false);

            // Create a new CreateNotificationForDeliveryChannelsRequest Object which supports the communication types and delivery channels
            var createNotificationForDeliveryChannelsRequestObject = new CreateNotificationForDeliveryChannelsRequest(
                body.NotificationType,
                body.UserIds,
                body.Timestamp,
                body.Properties,
                body.CorrelationIds);

            IDurableOrchestrationClient orchestrationClient = context.AsDurableFunctionsOpenApiContext().OrchestrationClient
                                                              ?? throw new OpenApiServiceMismatchException($"Operation {CreateNotificationsOperationId} has been invoked, but no Durable Orchestration Client is available on the OpenApi context.");

            await orchestrationClient.StartNewAsync(
                nameof(CreateAndDispatchNotificationsOrchestration),
                new TenantedFunctionData <CreateNotificationForDeliveryChannelsRequest>(context.CurrentTenantId !, createNotificationForDeliveryChannelsRequestObject, operationId)).ConfigureAwait(false);

            return(this.AcceptedResult(response.Location));
        }
Example #10
0
        public async Task <OpenApiResult> HandleTrigger(IOpenApiContext context, IWorkflowTrigger body)
        {
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId).ConfigureAwait(false);

            string delegatedTenantId = await this.marainServicesTenancy.GetDelegatedTenantIdForRequestingTenantAsync(tenant.Id).ConfigureAwait(false);

            var operationId = Guid.NewGuid();
            CreateOperationHeaders operationHeaders =
                await this.operationsControl.CreateOperationAsync(delegatedTenantId, operationId).ConfigureAwait(false);

            var envelope = new WorkflowMessageEnvelope(this.propertyBagFactory.Create(PropertyBagValues.Empty))
            {
                Trigger     = body,
                OperationId = operationId,
                TenantId    = context.CurrentTenantId,
            };

            var durableFunctionsOpenApiContext = (DurableFunctionsOpenApiContext)context;

            await durableFunctionsOpenApiContext.OrchestrationClient.StartNewWithCustomSerializationSettingsAsync(
                nameof(TriggerExecutionOrchestrator),
                operationId.ToString(),
                envelope,
                this.serializerSettingsProvider.Instance).ConfigureAwait(false);

            return(this.AcceptedResult(operationHeaders.Location));
        }
        private async Task CheckAccessPoliciesAsync(
            IOpenApiContext context,
            string path,
            string method,
            string operationId)
        {
            AccessControlPolicyResult result = await this.accessChecker.CheckAccessPolicyAsync(context, path, operationId, method).ConfigureAwait(false);

            if (result.ResultType == AccessControlPolicyResultType.NotAuthenticated)
            {
                Exception x = this.configuration.AccessPolicyUnauthenticatedResponse switch
                {
                    ResponseWhenUnauthenticated.Unauthorized => new OpenApiUnauthorizedException("Unauthorized"),
                    ResponseWhenUnauthenticated.Forbidden => OpenApiForbiddenException.WithoutProblemDetails("Forbidden"),
                    ResponseWhenUnauthenticated.ServerError => new OpenApiServiceMismatchException("Unauthenticated requests should not be reaching this service"),

                    _ => new OpenApiServiceMismatchException($"Unknown AccessPolicyUnauthenticatedResponse: {this.configuration.AccessPolicyUnauthenticatedResponse}"),
                };
                if (!string.IsNullOrWhiteSpace(result.Explanation))
                {
                    x.AddProblemDetailsExplanation(result.Explanation !); // ! required as netstandard2.0 lacks nullable attributes
                }

                throw x;
            }

            if (!result.Allow)
            {
                throw string.IsNullOrWhiteSpace(result.Explanation)
                                    ? OpenApiForbiddenException.WithoutProblemDetails("Forbidden")
                                    : OpenApiForbiddenException.WithProblemDetails("Forbidden", result.Explanation);
            }
        }
        public async Task <OpenApiResult> UpdateTenantAsync(
            string tenantId,
            JsonPatchDocument body,
            IOpenApiContext context)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (string.IsNullOrEmpty(tenantId))
            {
                throw new OpenApiBadRequestException("Bad request");
            }

            if (body is null)
            {
                throw new OpenApiBadRequestException();
            }

            if (tenantId == RootTenant.RootTenantId)
            {
                // Updates to the root tenant are blocked because in Marain services, the root
                // tenant is locally synthesized, and not fetched from the tenancy service.
                // This enables service-specific fallback settings to be configured on the root.
                // But it also means services will never see settings configured on the root
                // via the Marain.Tenancy service, and so, to avoid disappointment, we don't
                // let anyone try to do this.
                return(new OpenApiResult {
                    StatusCode = (int)HttpStatusCode.MethodNotAllowed
                });
            }

            try
            {
                string?name = null;
                Dictionary <string, object>?propertiesToSet = null;
                List <string>?propertiesToRemove            = null;

                foreach (Operation operation in body.Operations)
                {
                    if (operation.path == "/name")
                    {
                        if (operation.OperationType == OperationType.Replace &&
                            operation.value is string newTenantName)
                        {
                            name = newTenantName;
                        }
                        else
                        {
                            return(new OpenApiResult {
                                StatusCode = 422
                            });                                             // Unprocessable entity
                        }
                    }
                    else
                    {
                        if (operation.path.StartsWith("/properties/"))
                        {
                            string propertyName = operation.path[12..];
 public CheckAccessArguments(
     IOpenApiContext context,
     AccessCheckOperationDescriptor[] requests)
 {
     this.Context  = context;
     this.Requests = requests;
 }
        public async Task <OpenApiResult> MarkNotificationReadAsync(
            IOpenApiContext context,
            string notificationId)
        {
            // We're going to forward this on to the management API, which already implements all of the long running
            // operation semantics we would like here. At present, this is via the "batch update" endpoint - if at
            // some point in the future we add the ability to update a single notification status, we should switch
            // over to that in this code.

            // We can guarantee tenant Id is available because it's part of the Uri.
            // We don't actually need the tenant, but this method has the benefit of validating that the requesting
            // tenant is valid and is enrolled for this service.
            _ = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            BatchReadStatusUpdateRequestItem[] body = new[]
            {
                new BatchReadStatusUpdateRequestItem
                {
                    DeliveryChannelId = Constants.ApiDeliveryChannelId,
                    NewStatus         = UpdateNotificationReadStatusRequestNewStatus.Read,
                    NotificationId    = notificationId,
                    UpdateTimestamp   = DateTimeOffset.UtcNow,
                },
            };

            ApiResponse response = await this.managementApiClient.BatchReadStatusUpdateAsync(
                context.CurrentTenantId,
                body).ConfigureAwait(false);

            return(this.AcceptedResult(response.Headers["Location"]));
        }
        public async Task <OpenApiResult> GetNotificationAsync(
            IOpenApiContext context,
            string notificationId)
        {
            // We can guarantee tenant Id is available because it's part of the Uri.
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            IUserNotificationStore userNotificationStore =
                await this.userNotificationStoreFactory.GetUserNotificationStoreForTenantAsync(tenant).ConfigureAwait(false);

            UserNotification notifications;

            try
            {
                notifications = await userNotificationStore.GetByIdAsync(notificationId).ConfigureAwait(false);
            }
            catch (ArgumentException)
            {
                // This will happen if the supplied notification Id is invalid. Return a BadRequest response.
                throw new OpenApiBadRequestException("The supplied notificationId is not valid");
            }

            HalDocument response = await this.userNotificationMapper.MapAsync(notifications, context).ConfigureAwait(false);

            return(this.OkResult(response, "application/json"));
        }
Example #16
0
        /// <summary>
        /// Evaluates multiple policies concurrently, and aggregates the results, returning an Allow
        /// result if all policies says Allow, and otherwise returning a Deny result where the
        /// Explanation is formed by appending any Explanations produced by the individual policies.
        /// </summary>
        /// <param name="accessControlPolicies">
        /// The policies to evaluate and aggregate.
        /// </param>
        /// <param name="context">
        /// The context for which to perform the check.
        /// </param>
        /// <param name="requests">
        /// The list of operation descriptors to check.
        /// </param>
        /// <returns>
        /// A task that produces an <see cref="AccessControlPolicyResultType"/> indicating whether
        /// access is allowed, and if it is not, an optional textual explanation (which may be null).
        /// </returns>
        internal static async Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > EvaluteAccessPoliciesConcurrentlyAsync(
            IEnumerable <IOpenApiAccessControlPolicy> accessControlPolicies,
            IOpenApiContext context,
            params AccessCheckOperationDescriptor[] requests)
        {
            // Evaluate the set of requests with all policies simultaneously.
            IEnumerable <Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > > policyEvaluationTasks =
                accessControlPolicies.Select(
                    policy => policy.ShouldAllowAsync(
                        context,
                        requests));

            // Wait for all policy evaluation to complete.
            IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult>[] results = await Task.WhenAll(policyEvaluationTasks).ConfigureAwait(false);

            // "Roll up" the results. The results of the policy aggregation is a list of dictionaries, each dictionary
            // containing an entry for each of the requests supplied in the parameters. To build our result dictionary
            // we need to aggregate the entry for each request from each dictionary. To do this we use the
            // CombineResultTypes method for each result type, and concatenate any result explanations together.
            return(requests.ToDictionary(
                       request => request,
                       request =>
            {
                (AccessControlPolicyResultType resultType, string?explanation) = results.Aggregate(
                    (resultType: AccessControlPolicyResultType.Allowed, explanation: default(string)),
                    (acc, result) =>
                    (CombineResultTypes(acc.resultType, result[request].ResultType),
                     string.IsNullOrWhiteSpace(acc.explanation)
                        ? result[request].Explanation
                        : string.IsNullOrWhiteSpace(result[request].Explanation) ? acc.explanation : acc.explanation + "; " + result[request].Explanation));

                return new AccessControlPolicyResult(resultType, explanation);
            }));
Example #17
0
        public async Task <OpenApiResult> GetContentSummary(IOpenApiContext context, string slug, string contentId, string ifNoneMatch)
        {
            IContentStore contentStore = await this.contentStoreFactory.GetContentStoreForTenantAsync(context.CurrentTenantId).ConfigureAwait(false);

            ContentSummary result = await contentStore.GetContentSummaryAsync(contentId, slug).ConfigureAwait(false);

            string etag = EtagHelper.BuildEtag(nameof(ContentSummary), result.ETag);

            // If the etag in the result matches ifNoneMatch then we return 304 Not Modified
            if (EtagHelper.IsMatch(ifNoneMatch, etag))
            {
                return(this.NotModifiedResult());
            }

            HalDocument resultDocument = this.contentSummaryMapper.Map(result, new ResponseMappingContext {
                TenantId = context.CurrentTenantId
            });

            OpenApiResult response = this.OkResult(resultDocument);

            response.Results.Add(HeaderNames.ETag, etag);

            // Since content is immutable we can allow clients to cache it indefinitely.
            response.Results.Add(HeaderNames.CacheControl, Constants.CacheControlHeaderOptions.NeverExpire);

            return(response);
        }
 public Task <OpenApiResult> GetNotificationsAsync(
     IOpenApiContext context,
     string notificationId,
     int?maxItems,
     string?continuationToken)
 {
     return(Task.FromResult(this.NotImplementedResult()));
 }
Example #19
0
 /// <summary>
 /// Adds an entry to each of a set of audit services.
 /// </summary>
 /// <param name="auditSinks">A collection of audit services.</param>
 /// <param name="context">The current OpenApi context.</param>
 /// <param name="log">The audit log to write.</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 public static async Task LogAsync(
     this IEnumerable <IAuditLogSink> auditSinks,
     IOpenApiContext context,
     AuditLog log)
 {
     IEnumerable <Task> tasks = auditSinks.Select(x => x.LogAsync(context, log));
     await Task.WhenAll(tasks).ConfigureAwait(false);
 }
        /// <inheritdoc/>
        public Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > ShouldAllowAsync(
            IOpenApiContext context,
            params AccessCheckOperationDescriptor[] requests)
        {
            IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> result = requests.ToDictionary(request => request, request => this.ShouldAllow(request.OperationId));

            return(Task.FromResult(result));
        }
 public Task <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> > CheckAccessPoliciesAsync(
     IOpenApiContext context,
     params AccessCheckOperationDescriptor[] descriptors)
 {
     return(this.context.AccessCheckCalls == null
         ? Task.FromResult <IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> >(descriptors.ToDictionary(d => d, __ => Allowed))
         : this.context.AccessCheckCalls.GetTask(new CheckAccessArguments(context, descriptors)));
 }
        public async Task <OpenApiResult> CreateTemplateAsync(
            IOpenApiContext context,
            ICommunicationTemplate body,
            [OpenApiParameter("If-None-Match")]
            string etag)
        {
            if (string.IsNullOrWhiteSpace(body.NotificationType))
            {
                throw new OpenApiNotFoundException("The NotificationType was not found in the object");
            }

            if (string.IsNullOrWhiteSpace(body.ContentType))
            {
                throw new OpenApiNotFoundException("The ContentType was not found in the object");
            }

            // We can guarantee tenant Id is available because it's part of the Uri.
            ITenant tenant = await this.marainServicesTenancy.GetRequestingTenantAsync(context.CurrentTenantId !).ConfigureAwait(false);

            // Gets the AzureBlobTemplateStore
            INotificationTemplateStore store = await this.tenantedTemplateStoreFactory.GetTemplateStoreForTenantAsync(tenant).ConfigureAwait(false);

            try
            {
                if (body is EmailTemplate emailTemplate)
                {
                    emailTemplate.ETag = etag;
                    await store.CreateOrUpdate(body.NotificationType, CommunicationType.Email, emailTemplate.ETag, emailTemplate).ConfigureAwait(false);
                }
                else if (body is SmsTemplate smsTemplate)
                {
                    smsTemplate.ETag = etag;
                    await store.CreateOrUpdate(body.NotificationType, CommunicationType.Sms, smsTemplate.ETag, smsTemplate).ConfigureAwait(false);
                }
                else if (body is WebPushTemplate webPushTemplate)
                {
                    webPushTemplate.ETag = etag;
                    await store.CreateOrUpdate(body.NotificationType, CommunicationType.WebPush, webPushTemplate.ETag, webPushTemplate).ConfigureAwait(false);
                }
                else
                {
                    // this should be removed in future updates
                    throw new OpenApiNotFoundException($"The template for ContentType: {body.ContentType} is not a valid content type");
                }
            }
            catch (StorageException e)
            {
                if (e?.RequestInformation?.HttpStatusCode == (int)System.Net.HttpStatusCode.PreconditionFailed)
                {
                    throw new OpenApiBadRequestException("Precondition failure. Blob's ETag does not match ETag provided.");
                }

                throw;
            }

            return(this.OkResult());
        }
        public async Task <OpenApiResult> GetChildrenAsync(
            string tenantId,
            int?maxItems,
            string continuationToken,
            IOpenApiContext context)
        {
            if (string.IsNullOrEmpty(tenantId))
            {
                throw new OpenApiBadRequestException("Bad request");
            }

            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            try
            {
                TenantCollectionResult result = await this.tenantStore.GetChildrenAsync(tenantId, maxItems ?? 20, continuationToken).ConfigureAwait(false);

                HalDocument document = await this.tenantCollectionResultMapper.MapAsync(result).ConfigureAwait(false);

                if (result.ContinuationToken != null)
                {
                    OpenApiWebLink link = maxItems.HasValue
                        ? this.linkResolver.ResolveByOperationIdAndRelationType(GetChildrenOperationId, "next", ("tenantId", tenantId), ("continuationToken", result.ContinuationToken), ("maxItems", maxItems))
                        : this.linkResolver.ResolveByOperationIdAndRelationType(GetChildrenOperationId, "next", ("tenantId", tenantId), ("continuationToken", result.ContinuationToken));
                    document.AddLink("next", link);
                }

                var values = new List <(string, object?)> {
                    ("tenantId", tenantId)
                };
                if (maxItems.HasValue)
                {
                    values.Add(("maxItems", maxItems));
                }

                if (!string.IsNullOrEmpty(continuationToken))
                {
                    values.Add(("continuationToken", continuationToken));
                }

                OpenApiWebLink selfLink = this.linkResolver.ResolveByOperationIdAndRelationType(GetChildrenOperationId, "self", values.ToArray());
                document.AddLink("self", selfLink);

                return(this.OkResult(document, "application/json"));
            }
            catch (TenantNotFoundException)
            {
                return(this.NotFoundResult());
            }
            catch (TenantConflictException)
            {
                return(this.ConflictResult());
            }
        }
Example #24
0
 /// <inheritdoc />
 public AuditLog BuildAuditLog(IOpenApiContext context, object result, OpenApiOperation operation)
 {
     return(new AuditLog(operation.OperationId)
     {
         CreatedDateTimeUtc = DateTimeOffset.UtcNow,
         Result = 200,
         TenantId = context.CurrentTenantId,
         UserId = context.CurrentPrincipal?.Identity?.Name,
     });
 }
Example #25
0
        public Task <OpenApiResult> ShowSecretPet(IOpenApiContext openApiContext)
        {
            if (openApiContext.CurrentPrincipal?.IsInRole("admin") == true)
            {
                return(this.MapAndReturnPetAsync(this.secretPet));
            }

            return(Task.FromResult(new OpenApiResult {
                StatusCode = (int)HttpStatusCode.Unauthorized
            }));
        }
Example #26
0
 /// <inheritdoc/>
 public async Task AuditResultAsync(IOpenApiContext context, object result, OpenApiOperation operation)
 {
     if (this.IsAuditingEnabled)
     {
         AuditLog?log = this.BuildAuditLog(context, result, operation);
         if (log != null)
         {
             await this.auditSinks.LogAsync(context, log).ConfigureAwait(false);
         }
     }
 }
Example #27
0
        /// <summary>
        /// An extension method that provides simpler syntax when using the <see cref="IOpenApiAccessChecker"/>
        /// to check access for a single operation.
        /// </summary>
        /// <param name="checker">The underlying <see cref="IOpenApiAccessChecker"/> to use.</param>
        /// <param name="context">The current <see cref="IOpenApiContext"/>.</param>
        /// <param name="path">The request path.</param>
        /// <param name="operationId">The request Operation Id.</param>
        /// <param name="httpMethod">The request Http method.</param>
        /// <returns>A task that resolves to the result of the access check.</returns>
        public static async Task <AccessControlPolicyResult> CheckAccessPolicyAsync(
            this IOpenApiAccessChecker checker,
            IOpenApiContext context,
            string path,
            string operationId,
            string httpMethod)
        {
            var request = new AccessCheckOperationDescriptor(path, operationId, httpMethod);
            IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> result = await checker.CheckAccessPoliciesAsync(context, request).ConfigureAwait(false);

            return(result.Values.Single());
        }
Example #28
0
        /// <inheritdoc/>
        public async Task AuditFailureAsync(IOpenApiContext context, int statusCode, OpenApiOperation operation)
        {
            if (this.IsAuditingEnabled)
            {
                var log = new AuditLog(operation.OperationId)
                {
                    Result = statusCode,
                    UserId = context.CurrentPrincipal?.Identity?.Name,
                };

                await this.auditSinks.LogAsync(context, log).ConfigureAwait(false);
            }
        }
Example #29
0
 /// <summary>
 /// Initializes a new instance of the <see cref="UserNotificationsMappingContext"/> class.
 /// </summary>
 /// <param name="openApiContext">The <see cref="OpenApiContext"/>.</param>
 /// <param name="userId">The <see cref="UserId"/>.</param>
 /// <param name="sinceNotificationId">The <see cref="SinceNotificationId"/>.</param>
 /// <param name="maxItems">The <see cref="MaxItems"/>.</param>
 /// <param name="continuationToken">The <see cref="ContinuationToken"/>.</param>
 public UserNotificationsMappingContext(
     IOpenApiContext openApiContext,
     string userId,
     string?sinceNotificationId,
     int maxItems,
     string?continuationToken)
 {
     this.OpenApiContext      = openApiContext;
     this.SinceNotificationId = sinceNotificationId;
     this.MaxItems            = maxItems;
     this.ContinuationToken   = continuationToken;
     this.UserId = userId;
 }
Example #30
0
        /// <inheritdoc/>
        public async Task <TResponse> HandleRequestAsync(string path, string method, TRequest request, object parameters)
        {
            IOpenApiContext context = await this.BuildContextAsync(request, parameters).ConfigureAwait(false);

            // Try to find an Open API operation which matches the incoming request.
            if (this.matcher.FindOperationPathTemplate(path, method, out OpenApiOperationPathTemplate? operationPathTemplate))
            {
                // Now execute the operation
                return(await this.operationInvoker.InvokeAsync(path, method, request, operationPathTemplate, context).ConfigureAwait(false));
            }

            // We didn't find an operation which correspons to the path and method in the OpenAPI document
            return(this.BuildServiceOperationNotFoundResult());
        }