Skip to content

Commit

Permalink
Move additional modules/extensions to shared (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonpollett authored Mar 26, 2020
1 parent ee6e0f5 commit 271e4f7
Show file tree
Hide file tree
Showing 31 changed files with 976 additions and 0 deletions.
28 changes: 28 additions & 0 deletions Microsoft.Health.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Health.Abstractions", "src\Microsoft.Health.Abstractions\Microsoft.Health.Abstractions.csproj", "{E0CD7A0A-116D-4612-83BE-0DE036DADDF1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Api", "src\Microsoft.Health.Api\Microsoft.Health.Api.csproj", "{47D87BAA-D779-41A4-BC08-496EA36DC394}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Core", "src\Microsoft.Health.Core\Microsoft.Health.Core.csproj", "{F75E1C38-B407-4040-94B0-1AE07C05D6EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Api.UnitTests", "src\Microsoft.Health.Api.UnitTests\Microsoft.Health.Api.UnitTests.csproj", "{6E6F2E4B-DAF7-46B9-8589-045237AD65CE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.Core.UnitTests", "src\Microsoft.Health.Core.UnitTests\Microsoft.Health.Core.UnitTests.csproj", "{3670CFEA-068C-497A-8123-E149820F02DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer", "src\Microsoft.Health.SqlServer\Microsoft.Health.SqlServer.csproj", "{CF5D97F8-DE8F-4965-923D-82CA40CC9E49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer.Api", "src\Microsoft.Health.SqlServer.Api\Microsoft.Health.SqlServer.Api.csproj", "{561B1075-FA22-4D4E-881B-366230423B2D}"
Expand Down Expand Up @@ -51,6 +59,22 @@ Global
{E0CD7A0A-116D-4612-83BE-0DE036DADDF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0CD7A0A-116D-4612-83BE-0DE036DADDF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0CD7A0A-116D-4612-83BE-0DE036DADDF1}.Release|Any CPU.Build.0 = Release|Any CPU
{47D87BAA-D779-41A4-BC08-496EA36DC394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47D87BAA-D779-41A4-BC08-496EA36DC394}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47D87BAA-D779-41A4-BC08-496EA36DC394}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47D87BAA-D779-41A4-BC08-496EA36DC394}.Release|Any CPU.Build.0 = Release|Any CPU
{F75E1C38-B407-4040-94B0-1AE07C05D6EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F75E1C38-B407-4040-94B0-1AE07C05D6EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F75E1C38-B407-4040-94B0-1AE07C05D6EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F75E1C38-B407-4040-94B0-1AE07C05D6EE}.Release|Any CPU.Build.0 = Release|Any CPU
{6E6F2E4B-DAF7-46B9-8589-045237AD65CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E6F2E4B-DAF7-46B9-8589-045237AD65CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E6F2E4B-DAF7-46B9-8589-045237AD65CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E6F2E4B-DAF7-46B9-8589-045237AD65CE}.Release|Any CPU.Build.0 = Release|Any CPU
{3670CFEA-068C-497A-8123-E149820F02DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3670CFEA-068C-497A-8123-E149820F02DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3670CFEA-068C-497A-8123-E149820F02DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3670CFEA-068C-497A-8123-E149820F02DC}.Release|Any CPU.Build.0 = Release|Any CPU
{CF5D97F8-DE8F-4965-923D-82CA40CC9E49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF5D97F8-DE8F-4965-923D-82CA40CC9E49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF5D97F8-DE8F-4965-923D-82CA40CC9E49}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -76,6 +100,10 @@ Global
{614DE061-52A0-4471-A3F1-50C9C907FFDB} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{CA276939-8071-4734-9FE4-ADC825B72116} = {B70945F4-01A6-4351-955B-C4A2943B5E3B}
{E0CD7A0A-116D-4612-83BE-0DE036DADDF1} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{47D87BAA-D779-41A4-BC08-496EA36DC394} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{F75E1C38-B407-4040-94B0-1AE07C05D6EE} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{6E6F2E4B-DAF7-46B9-8589-045237AD65CE} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{3670CFEA-068C-497A-8123-E149820F02DC} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{CF5D97F8-DE8F-4965-923D-82CA40CC9E49} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{561B1075-FA22-4D4E-881B-366230423B2D} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{7650CF08-00B4-419B-8AF9-26E4079F08F2} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
Expand Down
2 changes: 2 additions & 0 deletions build/.vsts-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
trigger:
- master

pr: none

name: $(SourceBranchName)-$(Date:yyyyMMdd)$(Rev:-r)
variables:
buildConfiguration: 'Release'
Expand Down
1 change: 1 addition & 0 deletions nuget.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<!-- When <clear /> is present, previously defined sources are ignored -->
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="Microsoft Health OSS" value="https://microsofthealthoss.pkgs.visualstudio.com/FhirServer/_packaging/Public/nuget/v3/index.json" />
</packageSources>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.Health.Api.Features.Security;
using Xunit;

namespace Microsoft.Health.Api.UnitTests.Features.Security
{
public class SecurityHeadersHelperTests
{
[Fact]
public async void GivenANullContext_WhenSettingSecurityHeaders_ThenExceptionIsThrown()
{
await Assert.ThrowsAsync<ArgumentNullException>(async () => await SecurityHeadersHelper.SetSecurityHeaders(null));
}

[Fact]
public async void GivenAnIncorrectType_WhenSettingSecurityHeaders_ThenExceptionIsThrown()
{
int notAContext = 1;

await Assert.ThrowsAsync<ArgumentException>(async () => await SecurityHeadersHelper.SetSecurityHeaders(notAContext));
}

[Fact]
public async void GivenAContext_WhenSettingSecurityHeaders_TheXContentTypeOptionsHeaderIsSet()
{
var defaultHttpContext = new DefaultHttpContext();
await SecurityHeadersHelper.SetSecurityHeaders(defaultHttpContext);

Assert.NotNull(defaultHttpContext.Response.Headers);
Assert.NotEmpty(defaultHttpContext.Response.Headers);
Assert.True(defaultHttpContext.Response.Headers.TryGetValue("X-Content-Type-Options", out StringValues headerValue));
Assert.Equal("nosniff", headerValue);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
<PackageReference Include="NSubstitute" Version="4.2.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.Health.Api\Microsoft.Health.Api.csproj" />
</ItemGroup>
</Project>
116 changes: 116 additions & 0 deletions src/Microsoft.Health.Api.UnitTests/Modules/CorsModuleTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Health.Api.Configuration;
using Microsoft.Health.Api.Features.Cors;
using Microsoft.Health.Api.Modules;
using NSubstitute;
using Xunit;

namespace Microsoft.Health.Api.UnitTests.Modules
{
public class CorsModuleTests
{
private readonly CorsModule _corsModule;
private readonly CorsConfiguration _corsConfiguration = Substitute.For<CorsConfiguration>();
private readonly IServiceCollection _servicesCollection = Substitute.For<IServiceCollection>();

public CorsModuleTests()
{
var apiConfiguration = Substitute.For<IApiConfiguration>();
apiConfiguration.Cors.Returns(_corsConfiguration);
_corsModule = new CorsModule(apiConfiguration);
}

[Fact]
public void GivenACorsConfiguration_WhenNoValuesSet_PolicyHasOnlyDefaults()
{
_corsModule.Load(_servicesCollection);

CorsPolicy corsPolicy = _corsModule.DefaultCorsPolicy;
Assert.Empty(corsPolicy.Origins);
Assert.Empty(corsPolicy.Headers);
Assert.Empty(corsPolicy.Methods);
Assert.False(corsPolicy.SupportsCredentials);
Assert.Null(corsPolicy.PreflightMaxAge);
}

[Fact]
public void GivenACorsConfiguration_WhenAllOriginsSet_PolicyHasAllowAnyOrigin()
{
_corsConfiguration.Origins.Add("*");
_corsModule.Load(_servicesCollection);

Assert.True(_corsModule.DefaultCorsPolicy.AllowAnyOrigin);
}

[Fact]
public void GivenACorsConfiguration_WhenAllMethodsSet_PolicyHasAllowAnyMethod()
{
_corsConfiguration.Methods.Add("*");
_corsModule.Load(_servicesCollection);

Assert.True(_corsModule.DefaultCorsPolicy.AllowAnyMethod);
}

[Fact]
public void GivenACorsConfiguration_WhenAllHeadersSet_PolicyHasAllowAnyHeader()
{
_corsConfiguration.Headers.Add("*");
_corsModule.Load(_servicesCollection);

Assert.True(_corsModule.DefaultCorsPolicy.AllowAnyHeader);
}

[Fact]
public void GivenACorsConfiguration_WhenAllowCredentials_PolicyHasSupportsCredentials()
{
_corsConfiguration.AllowCredentials = true;
_corsModule.Load(_servicesCollection);

Assert.True(_corsModule.DefaultCorsPolicy.SupportsCredentials);
}

[Fact]
public void GivenACorsConfiguration_WhenMaxAgeSet_PolicyHasMaxAge()
{
_corsConfiguration.MaxAge = 100;
_corsModule.Load(_servicesCollection);

Assert.Equal(TimeSpan.FromSeconds(100), _corsModule.DefaultCorsPolicy.PreflightMaxAge);
}

[Fact]
public void GivenACorsConfiguration_WhenMultipleValuesSet_PolicyHasSpecifiedValues()
{
_corsConfiguration.Origins.Add("https://example.com");
_corsConfiguration.Origins.Add("https://contoso");

_corsConfiguration.Methods.Add("PATCH");
_corsConfiguration.Methods.Add("DELETE");

_corsConfiguration.Headers.Add("authorization");
_corsConfiguration.Headers.Add("content-type");

_corsModule.Load(_servicesCollection);

Assert.Equal(2, _corsModule.DefaultCorsPolicy.Origins.Count);
Assert.Equal(2, _corsModule.DefaultCorsPolicy.Methods.Count);
Assert.Equal(2, _corsModule.DefaultCorsPolicy.Headers.Count);

Assert.Contains("https://example.com", _corsModule.DefaultCorsPolicy.Origins);
Assert.Contains("https://contoso", _corsModule.DefaultCorsPolicy.Origins);

Assert.Contains("PATCH", _corsModule.DefaultCorsPolicy.Methods);
Assert.Contains("DELETE", _corsModule.DefaultCorsPolicy.Methods);

Assert.Contains("authorization", _corsModule.DefaultCorsPolicy.Headers);
Assert.Contains("content-type", _corsModule.DefaultCorsPolicy.Headers);
}
}
}
10 changes: 10 additions & 0 deletions src/Microsoft.Health.Api/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Resources;
using System.Runtime.CompilerServices;

[assembly: NeutralResourcesLanguage("en-us")]
[assembly: InternalsVisibleTo("Microsoft.Health.Api.UnitTests")]
14 changes: 14 additions & 0 deletions src/Microsoft.Health.Api/Configuration/IApiConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using Microsoft.Health.Api.Features.Cors;

namespace Microsoft.Health.Api.Configuration
{
public interface IApiConfiguration
{
CorsConfiguration Cors { get; }
}
}
22 changes: 22 additions & 0 deletions src/Microsoft.Health.Api/Features/Cors/CorsConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;

namespace Microsoft.Health.Api.Features.Cors
{
public class CorsConfiguration
{
public IList<string> Origins { get; } = new List<string>();

public IList<string> Headers { get; } = new List<string>();

public IList<string> Methods { get; } = new List<string>();

public int? MaxAge { get; set; }

public bool AllowCredentials { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/Microsoft.Health.Api/Features/Cors/CorsConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

namespace Microsoft.Health.Api.Features.Cors
{
public static class CorsConstants
{
public const string DefaultCorsPolicy = "DefaultCorsPolicy";
}
}
32 changes: 32 additions & 0 deletions src/Microsoft.Health.Api/Features/Headers/BaseHeadersMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Threading.Tasks;
using EnsureThat;
using Microsoft.AspNetCore.Http;
using Microsoft.Health.Api.Features.Security;

namespace Microsoft.Health.Api.Features.Headers
{
public class BaseHeadersMiddleware
{
private readonly RequestDelegate _next;

public BaseHeadersMiddleware(RequestDelegate next)
{
EnsureArg.IsNotNull(next, nameof(next));

_next = next;
}

public async Task Invoke(HttpContext context)
{
context.Response.OnStarting(SecurityHeadersHelper.SetSecurityHeaders, state: context);

// Call the next delegate/middleware in the pipeline
await _next(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using Microsoft.AspNetCore.Builder;

namespace Microsoft.Health.Api.Features.Headers
{
public static class BaseHeadersMiddlewareExtensions
{
public static IApplicationBuilder UseBaseHeaders(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<BaseHeadersMiddleware>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Threading.Tasks;
using EnsureThat;
using Microsoft.AspNetCore.Http;

namespace Microsoft.Health.Api.Features.Security
{
internal static class SecurityHeadersHelper
{
private const string XContentTypeOptions = "X-Content-Type-Options";
private const string XContentTypeOptionsValue = "nosniff";

internal static Task SetSecurityHeaders(object context)
{
EnsureArg.IsNotNull(context, nameof(context));
EnsureArg.IsTrue(context is HttpContext, nameof(context));
var httpContext = (HttpContext)context;

httpContext.Response.Headers.TryAdd(XContentTypeOptions, XContentTypeOptionsValue);

return Task.CompletedTask;
}
}
}
Loading

0 comments on commit 271e4f7

Please sign in to comment.