private void Log(AuditAction auditAction, HttpStatusCode?statusCode, HttpContext httpContext, IClaimsExtractor claimsExtractor) { IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.RequestContext; string auditEventType = fhirRequestContext.AuditEventType; // We are retaining AuditEventType when CustomError occurs. Below check ensures that the audit log is not entered for the custom error request httpContext.Request.RouteValues.TryGetValue("action", out object actionName); if (!string.IsNullOrEmpty(actionName?.ToString()) && KnownRoutes.CustomError.Contains(actionName?.ToString(), StringComparison.OrdinalIgnoreCase)) { return; } // Audit the call if an audit event type is associated with the action. // Since AuditEventType holds value for both AuditEventType and FhirAnonymousOperationType ensure that we only log the AuditEventType if (!string.IsNullOrEmpty(auditEventType) && !FhirAnonymousOperationTypeList.Contains(auditEventType, StringComparer.OrdinalIgnoreCase)) { _auditLogger.LogAudit( auditAction, operation: auditEventType, resourceType: fhirRequestContext.ResourceType, requestUri: fhirRequestContext.Uri, statusCode: statusCode, correlationId: fhirRequestContext.CorrelationId, callerIpAddress: httpContext.Connection?.RemoteIpAddress?.ToString(), callerClaims: claimsExtractor.Extract(), customHeaders: _auditHeaderReader.Read(httpContext)); } }
public async Task <CreateExportResponse> Handle(CreateExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); if (await _authorizationService.CheckAccess(DataActions.Export) != DataActions.Export) { throw new UnauthorizedFhirActionException(); } IReadOnlyCollection <KeyValuePair <string, string> > requestorClaims = _claimsExtractor.Extract()? .OrderBy(claim => claim.Key, StringComparer.Ordinal).ToList(); // Compute the hash of the job. var hashObject = new { request.RequestUri, RequestorClaims = requestorClaims, }; string hash = JsonConvert.SerializeObject(hashObject).ComputeHash(); // Check to see if a matching job exists or not. If a matching job exists, we will return that instead. // Otherwise, we will create a new export job. This will be a best effort since the likelihood of this happen should be small. ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByHashAsync(hash, cancellationToken); if (outcome == null) { var jobRecord = new ExportJobRecord(request.RequestUri, request.ResourceType, hash, requestorClaims, request.Since); outcome = await _fhirOperationDataStore.CreateExportJobAsync(jobRecord, cancellationToken); } return(new CreateExportResponse(outcome.JobRecord.Id)); }
public async Task <CreateExportResponse> Handle(CreateExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); if (await _authorizationService.CheckAccess(DataActions.Export, cancellationToken) != DataActions.Export) { throw new UnauthorizedFhirActionException(); } IReadOnlyCollection <KeyValuePair <string, string> > requestorClaims = _claimsExtractor.Extract()? .OrderBy(claim => claim.Key, StringComparer.Ordinal).ToList(); // Compute the hash of the job. var hashObject = new { request.RequestUri, RequestorClaims = requestorClaims, }; string hash = JsonConvert.SerializeObject(hashObject).ComputeHash(); string storageAccountConnectionHash = string.IsNullOrEmpty(_exportJobConfiguration.StorageAccountConnection) ? string.Empty : StringExtensions.ComputeHash(_exportJobConfiguration.StorageAccountConnection); // Check to see if a matching job exists or not. If a matching job exists, we will return that instead. // Otherwise, we will create a new export job. This will be a best effort since the likelihood of this happen should be small. ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByHashAsync(hash, cancellationToken); var filters = ParseFilter(request.Filters); ExportJobFormatConfiguration formatConfiguration = ParseFormat(request.FormatName, request.ContainerName != null); if (outcome == null) { var jobRecord = new ExportJobRecord( request.RequestUri, request.RequestType, formatConfiguration.Format, request.ResourceType, filters, hash, _exportJobConfiguration.RollingFileSizeInMB, requestorClaims, request.Since, request.GroupId, storageAccountConnectionHash, _exportJobConfiguration.StorageAccountUri, request.AnonymizationConfigurationLocation, request.AnonymizationConfigurationFileETag, _exportJobConfiguration.MaximumNumberOfResourcesPerQuery, _exportJobConfiguration.NumberOfPagesPerCommit, request.ContainerName); outcome = await _fhirOperationDataStore.CreateExportJobAsync(jobRecord, cancellationToken); } return(new CreateExportResponse(outcome.JobRecord.Id)); }
public AuditHelperTests() { _dicomRequestContext.Uri.Returns(Uri); _dicomRequestContext.CorrelationId.Returns(CorrelationId); _dicomRequestContextAccessor.RequestContext = _dicomRequestContext; _httpContext.Connection.RemoteIpAddress = CallerIpAddress; _claimsExtractor.Extract().Returns(Claims); _auditHelper = new AuditHelper(_dicomRequestContextAccessor, _auditLogger, _auditHeaderReader); }
public AuditHelperTests() { _fhirRequestContext.Uri.Returns(Uri); _fhirRequestContext.CorrelationId.Returns(CorrelationId); _fhirRequestContext.ResourceType.Returns("Patient"); _fhirRequestContextAccessor.FhirRequestContext = _fhirRequestContext; _httpContext.Connection.RemoteIpAddress = CallerIpAddress; _claimsExtractor.Extract().Returns(Claims); _auditHelper = new AuditHelper(_fhirRequestContextAccessor, _auditLogger, _auditHeaderReader); }
public async Task <CreateExportResponse> Handle(CreateExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); IReadOnlyCollection <KeyValuePair <string, string> > requestorClaims = _claimsExtractor.Extract()? .OrderBy(claim => claim.Key, StringComparer.Ordinal).ToList(); // Compute the hash of the job. var hashObject = new { request.RequestUri, RequestorClaims = requestorClaims, request.DestinationInfo, }; string hash = JsonConvert.SerializeObject(hashObject).ComputeHash(); // Check to see if a matching job exists or not. If a matching job exists, we will return that instead. // Otherwise, we will create a new export job. This will be a best effort since the likelihood of this happen should be small. ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByHashAsync(hash, cancellationToken); if (outcome == null) { // Remove the connection settings from the request URI before we store it in the secret store. NameValueCollection queryParameters = HttpUtility.ParseQueryString(request.RequestUri.Query); queryParameters.Remove(KnownQueryParameterNames.DestinationType); queryParameters.Remove(KnownQueryParameterNames.DestinationConnectionSettings); var uriBuilder = new UriBuilder(request.RequestUri); uriBuilder.Query = queryParameters.ToString(); var jobRecord = new ExportJobRecord(uriBuilder.Uri, request.ResourceType, hash, requestorClaims); // Store the destination secret. try { await _secretStore.SetSecretAsync(jobRecord.SecretName, request.DestinationInfo.ToJson(), cancellationToken); } catch (SecretStoreException sse) { throw new OperationFailedException(string.Format(Resources.OperationFailed, OperationsConstants.Export, sse.Message), sse.ResponseStatusCode); } outcome = await _fhirOperationDataStore.CreateExportJobAsync(jobRecord, cancellationToken); } return(new CreateExportResponse(outcome.JobRecord.Id)); }
public AuditHelperTests() { _fhirRequestContext.Uri.Returns(Uri); _fhirRequestContext.CorrelationId.Returns(CorrelationId); _fhirRequestContextAccessor.FhirRequestContext = _fhirRequestContext; _auditEventTypeMapping.GetAuditEventType(ControllerName, AnonymousActionName).Returns((string)null); _auditEventTypeMapping.GetAuditEventType(ControllerName, NonAnonymousActionName).Returns(AuditEventType); _httpContext.Connection.RemoteIpAddress = CallerIpAddress; _claimsExtractor.Extract().Returns(Claims); _auditHelper = new AuditHelper(_fhirRequestContextAccessor, _auditEventTypeMapping, _auditLogger, NullLogger <AuditHelper> .Instance, _auditHeaderReader); }
/// <inheritdoc /> public ResourceWrapper Create(ResourceElement resource, bool deleted, bool keepMeta) { RawResource rawResource = _rawResourceFactory.Create(resource, keepMeta); IReadOnlyCollection <SearchIndexEntry> searchIndices = _searchIndexer.Extract(resource); IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.FhirRequestContext; return(new ResourceWrapper( resource, rawResource, new ResourceRequest(fhirRequestContext.Method, fhirRequestContext.Uri), deleted, searchIndices, _compartmentIndexer.Extract(resource.InstanceType, searchIndices), _claimsExtractor.Extract())); }
public AuditHelperTests() { Type mockControllerType = typeof(MockController); var actionDescriptors = new List <ActionDescriptor>() { new ControllerActionDescriptor() { ControllerName = ControllerName, ActionName = AnonymousMethodName, MethodInfo = mockControllerType.GetMethod(AnonymousMethodName), }, new ControllerActionDescriptor() { ControllerName = ControllerName, ActionName = AudittedMethodName, MethodInfo = mockControllerType.GetMethod(AudittedMethodName), }, new ControllerActionDescriptor() { ControllerName = ControllerName, ActionName = NoAttributeMethodName, MethodInfo = mockControllerType.GetMethod(NoAttributeMethodName), }, new PageActionDescriptor() { }, }; var actionDescriptorCollection = new ActionDescriptorCollection(actionDescriptors, 1); _actionDescriptorCollectionProvider.ActionDescriptors.Returns(actionDescriptorCollection); _fhirRequestContext.Uri.Returns(Uri); _fhirRequestContext.CorrelationId.Returns(CorrelationId); _fhirRequestContextAccessor.FhirRequestContext = _fhirRequestContext; _httpContext.Connection.RemoteIpAddress = CallerIpAddress; _claimsExtractor.Extract().Returns(Claims); _auditHelper = new AuditHelper(_actionDescriptorCollectionProvider, _fhirRequestContextAccessor, _auditLogger, NullLogger <AuditHelper> .Instance); ((IStartable)_auditHelper).Start(); }
/// <inheritdoc /> public ResourceWrapper Create(ResourceElement resource, bool deleted, bool keepMeta) { RawResource rawResource = _rawResourceFactory.Create(resource, keepMeta); IReadOnlyCollection <SearchIndexEntry> searchIndices = _searchIndexer.Extract(resource); string searchParamHash = _searchParameterDefinitionManager.GetSearchParameterHashForResourceType(resource.InstanceType); ExtractMinAndMaxValues(searchIndices); IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.FhirRequestContext; return(new ResourceWrapper( resource, rawResource, new ResourceRequest(fhirRequestContext.Method, fhirRequestContext.Uri), deleted, searchIndices, _compartmentIndexer.Extract(resource.InstanceType, searchIndices), _claimsExtractor.Extract(), searchParamHash)); }
private void Log(AuditAction auditAction, HttpStatusCode?statusCode, HttpContext httpContext, IClaimsExtractor claimsExtractor) { IRequestContext dicomRequestContext = _dicomRequestContextAccessor.DicomRequestContext; string auditEventType = dicomRequestContext.AuditEventType; // Audit the call if an audit event type is associated with the action. if (!string.IsNullOrEmpty(auditEventType)) { _auditLogger.LogAudit( auditAction, operation: auditEventType, requestUri: dicomRequestContext.Uri, statusCode: statusCode, correlationId: dicomRequestContext.CorrelationId, callerIpAddress: httpContext.Connection?.RemoteIpAddress?.ToString(), callerClaims: claimsExtractor.Extract(), customHeaders: _auditHeaderReader.Read(httpContext)); } }
private void Log(AuditAction auditAction, string controllerName, string actionName, HttpStatusCode?statusCode, string resourceType, HttpContext httpContext, IClaimsExtractor claimsExtractor) { string auditEventType = _auditEventTypeMapping.GetAuditEventType(controllerName, actionName); // Audit the call if an audit event type is associated with the action. if (auditEventType != null) { IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.FhirRequestContext; _auditLogger.LogAudit( auditAction, operation: auditEventType, resourceType: resourceType, requestUri: fhirRequestContext.Uri, statusCode: statusCode, correlationId: fhirRequestContext.CorrelationId, callerIpAddress: httpContext.Connection?.RemoteIpAddress?.ToString(), callerClaims: claimsExtractor.Extract()); } }
private void Log(AuditAction auditAction, string controllerName, string actionName, HttpStatusCode?statusCode, string resourceType, HttpContext httpContext, IClaimsExtractor claimsExtractor) { IFhirRequestContext fhirRequestContext = _fhirRequestContextAccessor.FhirRequestContext; // fhirRequestContext.AuditEventType will not be set in the case of an unauthorized call because the filter that sets it will not be executed string auditEventType = string.IsNullOrWhiteSpace(fhirRequestContext.AuditEventType) ? _auditEventTypeMapping.GetAuditEventType(controllerName, actionName) : fhirRequestContext.AuditEventType; // Audit the call if an audit event type is associated with the action. if (auditEventType != null) { _auditLogger.LogAudit( auditAction, operation: auditEventType, resourceType: resourceType, requestUri: fhirRequestContext.Uri, statusCode: statusCode, correlationId: fhirRequestContext.CorrelationId, callerIpAddress: httpContext.Connection?.RemoteIpAddress?.ToString(), callerClaims: claimsExtractor.Extract(), customHeaders: _auditHeaderReader.Read(httpContext)); } }
public async Task <CreateExportResponse> Handle(CreateExportRequest request, CancellationToken cancellationToken) { EnsureArg.IsNotNull(request, nameof(request)); if (await _authorizationService.CheckAccess(DataActions.Export) != DataActions.Export) { throw new UnauthorizedFhirActionException(); } IReadOnlyCollection <KeyValuePair <string, string> > requestorClaims = _claimsExtractor.Extract()? .OrderBy(claim => claim.Key, StringComparer.Ordinal).ToList(); // Compute the hash of the job. var hashObject = new { request.RequestUri, RequestorClaims = requestorClaims, }; string hash = JsonConvert.SerializeObject(hashObject).ComputeHash(); string storageAccountConnectionHash = string.IsNullOrEmpty(_exportJobConfiguration.StorageAccountConnection) ? string.Empty : Microsoft.Health.Core.Extensions.StringExtensions.ComputeHash(_exportJobConfiguration.StorageAccountConnection); // Check to see if a matching job exists or not. If a matching job exists, we will return that instead. // Otherwise, we will create a new export job. This will be a best effort since the likelihood of this happen should be small. ExportJobOutcome outcome = await _fhirOperationDataStore.GetExportJobByHashAsync(hash, cancellationToken); ExportJobFormatConfiguration formatConfiguration = null; if (request.FormatName != null) { formatConfiguration = _exportJobConfiguration.Formats?.FirstOrDefault( (ExportJobFormatConfiguration formatConfig) => formatConfig.Name.Equals(request.FormatName, StringComparison.OrdinalIgnoreCase)); if (formatConfiguration == null) { throw new BadRequestException(Resources.ExportFormatNotFound); } } formatConfiguration ??= _exportJobConfiguration.Formats?.FirstOrDefault( (ExportJobFormatConfiguration formatConfig) => formatConfig.Default); formatConfiguration ??= new ExportJobFormatConfiguration() { Format = request.ContainerName == null ? ExportFormatTags.ResourceName : $"{ExportFormatTags.Timestamp}-{ExportFormatTags.Id}/{ExportFormatTags.ResourceName}", }; if (outcome == null) { var jobRecord = new ExportJobRecord( request.RequestUri, request.RequestType, formatConfiguration.Format, request.ResourceType, hash, requestorClaims, request.Since, request.GroupId, storageAccountConnectionHash, _exportJobConfiguration.StorageAccountUri, request.AnonymizationConfigurationLocation, request.AnonymizationConfigurationFileETag, _exportJobConfiguration.MaximumNumberOfResourcesPerQuery, _exportJobConfiguration.NumberOfPagesPerCommit, request.ContainerName); outcome = await _fhirOperationDataStore.CreateExportJobAsync(jobRecord, cancellationToken); } return(new CreateExportResponse(outcome.JobRecord.Id)); }