Skip to content

Commit

Permalink
Add oauth2 implicit flow in Swagger security (#17)
Browse files Browse the repository at this point in the history
* Add oauth2 implicit flow in swagger security

* Dump version to 1.2.1

* Ignore health calls in opentelemetry

* Add Authorization roles
  • Loading branch information
devpro authored May 2, 2022
1 parent 7008cf6 commit c69bbeb
Show file tree
Hide file tree
Showing 16 changed files with 157 additions and 86 deletions.
16 changes: 9 additions & 7 deletions .docker/opentelemetry-collector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ exporters:
prometheus:
endpoint: "0.0.0.0:8889"
logging:
zipkin:
endpoint: "http://zipkin:9411/api/v2/spans"
format: proto
file:
path: /etc/output/logs.json
#zipkin:
# endpoint: "http://zipkin:9411/api/v2/spans"
# format: proto
#file:
# path: /etc/output/logs.json
otlp:
endpoint: tempo:4317
tls:
Expand All @@ -31,12 +31,14 @@ service:
pipelines:
logs:
receivers: [otlp]
exporters: [logging, file, loki]
#exporters: [logging, file, loki]
exporters: [logging, loki]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [logging, prometheus]
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging, zipkin, otlp]
#exporters: [logging, zipkin, otlp]
exporters: [logging, otlp]
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<PropertyGroup>
<!-- edit this value to change the current MAJOR.MINOR.PATCH version -->
<VersionPrefix>1.2.0</VersionPrefix>
<VersionPrefix>1.2.1</VersionPrefix>
</PropertyGroup>

<Choose>
Expand Down
16 changes: 8 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
version: "3.9"
services:
zipkin:
image: openzipkin/zipkin:latest
container_name: zipkin
ports:
- "9411:9411"
#zipkin:
# image: openzipkin/zipkin:latest
# container_name: zipkin
# ports:
# - "9411:9411"

otel-collector:
image: otel/opentelemetry-collector-contrib:latest
Expand All @@ -18,7 +18,7 @@ services:
- "8889:8889" # prometheus exporter
- "4317:4317" # oltp grpc receiver
depends_on:
- zipkin
#- zipkin
- grafana

prometheus:
Expand All @@ -39,7 +39,7 @@ services:
- "3200:3200"

loki:
image: grafana/loki:2.4.2
image: grafana/loki:latest
container_name: loki
command: [ "-config.file=/etc/loki/local-config.yaml" ]
ports:
Expand All @@ -58,5 +58,5 @@ services:
- GF_AUTH_DISABLE_LOGIN_FORM=true
depends_on:
- prometheus
- loki
#- loki
- tempo
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RabbidsIncubator.Samples.ServiceNowWebApiSample.Domain;

namespace RabbidsIncubator.Samples.ServiceNowWebApiSample.Controllers
{
[Authorize]
[ApiController]
[Route("configuration-item-relationships")]
public class ConfigurationItemRelationshipController : RabbidsIncubator.ServiceNowClient.Application.Mvc.ControllerBase
Expand Down
1 change: 0 additions & 1 deletion samples/WebApiSample/ImplicitUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
global using RabbidsIncubator.Samples.ServiceNowWebApiSample.Infrastructure.ServiceNowRestClient.DependencyInjection;
global using RabbidsIncubator.Samples.ServiceNowWebApiSample.Infrastructure.ServiceNowRestClient.MappingProfiles;
global using RabbidsIncubator.Samples.ServiceNowWebApiSample.Infrastructure.SqlServerClient.DependencyInjection;
global using RabbidsIncubator.Samples.ServiceNowWebApiSample.Infrastructure.SqlServerClient.MappingProfiles;
global using RabbidsIncubator.ServiceNowClient.Application.Builder;
global using RabbidsIncubator.ServiceNowClient.Application.DependencyInjection;
2 changes: 1 addition & 1 deletion samples/WebApiSample/WebApiSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.15.1" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions samples/WebApiSample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@
"OpenApi": {
"Title": "ServiceNow Client Web API sample",
"Version": "v1.0"
},
"Swagger": {
"SecurityDefinitionName": "oauth2"
}
}
2 changes: 1 addition & 1 deletion samples/WebApiSample/entities.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ targetApplication: WebApp
entities:
- name: Location
resourceName: locations
isAuthorizationRequired: false
#isAuthorizationRequired: false
queries:
findAll:
serviceNowRestApiTable: cmn_location
Expand Down
7 changes: 6 additions & 1 deletion src/Application.Generators/ControllerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ private static void GenerateController(GeneratorExecutionContext context, Models
namespace {namespaces.WebApi}.Controllers
{{");

if (entity.IsAuthorizationRequired)
if (entity.IsAuthorizationRequired && string.IsNullOrEmpty(entity.AuthorizationRoles))
{
sourceBuilder.Append(@"
[Authorize]");
}
else if (entity.IsAuthorizationRequired && !string.IsNullOrEmpty(entity.AuthorizationRoles))
{
sourceBuilder.Append($@"
[Authorize(Roles = ""{entity.AuthorizationRoles}"")]");
}

sourceBuilder.Append($@"
[ApiController]
Expand Down
5 changes: 5 additions & 0 deletions src/Application.Generators/Models/EntityModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class EntityModel
/// </summary>
public bool IsAuthorizationRequired { get; set; } = true;

/// <summary>
/// Comma separated roles to be set to the authorization.
/// </summary>
public string AuthorizationRoles { get; set; } = string.Empty;

/// <summary>
/// Queries.
/// </summary>
Expand Down
12 changes: 6 additions & 6 deletions src/Application/Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.3" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.23.1" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.23.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.2.0-beta1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.4" />
<PackageReference Include="Microsoft.Identity.Web" Version="1.24.1" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.24.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.2.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol.Logs" Version="1.0.0-rc8" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc8" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc8" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc8" />
<PackageReference Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.0.0-rc8" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
</ItemGroup>

<ItemGroup>
Expand Down
91 changes: 73 additions & 18 deletions src/Application/DependencyInjection/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ private static IServiceCollection AddOpenTelemetry(this IServiceCollection servi
builder.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(openTelemetryService));
builder.AddAspNetCoreInstrumentation(options =>
{
options.Filter = (httpContext) =>
{
var pathsToIgnore = "/health,/favicon.ico";

foreach (var path in pathsToIgnore.Split(','))
{
if (httpContext.Request.Path.StartsWithSegments(path))
{
return false;
}
}

return true;
};

options.RecordException = true;
if (enrichAction != default)
{
Expand Down Expand Up @@ -167,30 +182,70 @@ private static IServiceCollection AddSwaggerGenWithOpenApiInfo(this IServiceColl
c.SwaggerDoc(openApi.Version, openApi);
if (isSecured)
{
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
var securityName = configuration.GetSection("Swagger")?.GetValue<string>("SecurityDefinitionName");
if (securityName != null && securityName == "Bearer")
{
Description = "JWT Authorization header using the Bearer scheme.\r\n\r\nEnter your token in the text input below.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme.\r\n\r\nEnter your token in the text input below.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
}
else
{
var azureAd = configuration.GetSection(ConfigurationConstants.AzureAdConfigKey);
// see https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/README.md#add-security-definitions-and-requirements
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme()
{
new OpenApiSecurityScheme
Type = SecuritySchemeType.OAuth2,
Description = "Azure AAD Authentication",
Flows = new OpenApiOAuthFlows()
{
Reference = new OpenApiReference
// flow not possible for an API (requires SPA auth) and requires client secret
//AuthorizationCode = new OpenApiOAuthFlow() { AuthorizationUrl = ..., TokenUrl = new Uri($"{azureAd["Instance"]}{azureAd["TenantId"]}/oauth2/v2.0/token"), Scopes = ... }
// implicit flow used instead
Implicit = new OpenApiOAuthFlow
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
AuthorizationUrl = new Uri($"{azureAd["Instance"]}{azureAd["TenantId"]}/oauth2/v2.0/authorize"),
Scopes = { { $"api://{azureAd["ClientId"]}/access_as_user", "Access as user" } }
}
}
});

c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
new[] { $"api://{azureAd["ClientId"]}/access_as_user" }
}
});
}
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.5.1" />
<PackageReference Include="FluentAssertions" Version="6.6.0" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.110" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.XUnit" Version="1.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
Expand Down
74 changes: 37 additions & 37 deletions test/Application.UnitTests/Application.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>RabbidsIncubator.ServiceNowClient.Application.UnitTests</AssemblyName>
<RootNamespace>RabbidsIncubator.ServiceNowClient.Application.UnitTests</RootNamespace>
<ProjectGuid>{E268A5A8-245E-46D2-82FA-1EC8B682EB5E}</ProjectGuid>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.5.1" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.110" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Moq" Version="4.17.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Application\Application.csproj" />
</ItemGroup>

</Project>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>RabbidsIncubator.ServiceNowClient.Application.UnitTests</AssemblyName>
<RootNamespace>RabbidsIncubator.ServiceNowClient.Application.UnitTests</RootNamespace>
<ProjectGuid>{E268A5A8-245E-46D2-82FA-1EC8B682EB5E}</ProjectGuid>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.6.0" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.110" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Moq" Version="4.17.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Application\Application.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.5.1" />
<PackageReference Include="FluentAssertions" Version="6.6.0" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.110" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.5.1" />
<PackageReference Include="FluentAssertions" Version="6.6.0" />
<PackageReference Include="JunitXml.TestLogger" Version="3.0.110" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Withywoods.WebTesting" Version="1.4.6" />
<PackageReference Include="xunit" Version="2.4.1" />
Expand Down

0 comments on commit c69bbeb

Please sign in to comment.