Skip to content

Commit

Permalink
Merge branch 'feature/azure-ad-auth' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
rodolphocastro committed Mar 17, 2020
2 parents b63252e + 64080e4 commit 885280d
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 27 deletions.
2 changes: 2 additions & 0 deletions src/CellCms.Api/CellCms.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UserSecretsId>65dd841a-d95b-442c-8d61-dbc824e4f10f</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.1.0" />
</ItemGroup>

Expand Down
14 changes: 14 additions & 0 deletions src/CellCms.Api/Constants/CellScopes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace CellCms.Api.Constants
{
/// <summary>
/// Scopes para Cell CMS.
/// </summary>
public static class CellScopes
{
// A ideia aqui é armazenar todas as nossas strings "fixas" em um único lugar, pra caso precisemos alterar ficar fácil.
/// <summary>
/// Permite acesso ao SwaggerUi para testes da API.
/// </summary>
public const string AcessoSwagger = "api://cell-cms-dev/SwaggerUi.Acesso";
}
}
2 changes: 2 additions & 0 deletions src/CellCms.Api/Controllers/WeatherForecastController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

Expand All @@ -23,6 +24,7 @@ public WeatherForecastController(ILogger<WeatherForecastController> logger)
_logger = logger;
}

[Authorize]
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
Expand Down
18 changes: 1 addition & 17 deletions src/CellCms.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53765",
"sslPort": 44332
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CellCms.Api": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"launchUrl": "",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
21 changes: 21 additions & 0 deletions src/CellCms.Api/Settings/AzureAdSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace CellCms.Api.Settings
{
/// <summary>
/// Configurações do Azure AD.
/// </summary>
public class AzureAdSettings : IAzureAdSettings
{
/// <summary>
/// Chave para buscar as configurações.
/// </summary>
public const string SettingsKey = "AzureAd";

public string ClientId { get; set; }

public string TokenEndpoint { get; set; }

public string AuthorizeEndpoint { get; set; }

public string MetadataEndpoint { get; set; }
}
}
28 changes: 28 additions & 0 deletions src/CellCms.Api/Settings/IAzureAdSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace CellCms.Api.Settings
{
/// <summary>
/// Descreve as propriedades para configurar autenticação através do Azure AD.
/// </summary>
public interface IAzureAdSettings
{
/// <summary>
/// ClientId esperado.
/// </summary>
string ClientId { get; }

/// <summary>
/// Endpoint para obter access tokens.
/// </summary>
string TokenEndpoint { get; }

/// <summary>
/// Endpoint para obter autorização dos usuários.
/// </summary>
string AuthorizeEndpoint { get; }

/// <summary>
/// Endpoint para buscar o well-known document.
/// </summary>
string MetadataEndpoint { get; }
}
}
44 changes: 37 additions & 7 deletions src/CellCms.Api/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CellCms.Api.Settings;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;

namespace CellCms.Api
{
Expand All @@ -25,6 +22,38 @@ public Startup(IConfiguration configuration)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Buscando as nossas configurações do Azure AD
var aadSettings = Configuration.GetSection(AzureAdSettings.SettingsKey).Get<AzureAdSettings>();

if (aadSettings is null)
{
throw new InvalidOperationException("As configurações do Azure AD são obrigatórias para o Cell CMS.");
}

// Adicionando os serviços de autenticação
services
.AddAuthentication(c =>
{
c.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; // Definindo que os JWTs serão nosso schema de autenticação padrão
c.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; // Definindo que os JWTs serão nosso schema padrão para challenges de autenticação
})
.AddJwtBearer(c =>
{
c.IncludeErrorDetails = true; // Garantindo que o Middleware nos retorno erros detalhados, em produção pode ser melhor desabilitar
c.SaveToken = true; // Indica que o Token deve ser salvo
// As linhas abaixo configuram a validação do Token, com base nas nossas configurações
c.MetadataAddress = aadSettings.MetadataEndpoint;
c.TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = aadSettings.ClientId,
ValidateAudience = true,
// Na documentação (https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#update-your-code-to-handle-multiple-issuer-values)
// recomenda-se validar Guid-a-Guid os issuers para cada tenant que puder utilizar nosso App.
// Como nossa ideia aqui é fazer apenas o App, não vamos fazer este passo
ValidateIssuer = false
};
});

// Adicionando a geração do swagger.json
services.AddCellSwagger(Configuration);

Expand All @@ -46,6 +75,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Configuration;
using CellCms.Api.Settings;
using Microsoft.Extensions.Configuration;
using System;

namespace Microsoft.AspNetCore.Builder
Expand Down Expand Up @@ -38,10 +39,13 @@ public static IApplicationBuilder UseCellSwaggerUi(this IApplicationBuilder app,
throw new ArgumentNullException(nameof(app));
}

var aadSettings = configuration.GetSection(AzureAdSettings.SettingsKey).Get<AzureAdSettings>();

app.UseSwaggerUI(cfg =>
{
cfg.RoutePrefix = string.Empty;
cfg.SwaggerEndpoint("/swagger/v1/swagger.json", "Cell CMS API");
cfg.OAuthClientId(aadSettings.ClientId);
});

return app;
Expand Down
31 changes: 30 additions & 1 deletion src/CellCms.Api/Swagger/CellSwaggerServicesExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Microsoft.Extensions.Configuration;
using CellCms.Api.Constants;
using CellCms.Api.Settings;
using CellCms.Api.Swagger;
using Microsoft.Extensions.Configuration;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;

namespace Microsoft.Extensions.DependencyInjection
{
Expand All @@ -22,6 +26,8 @@ public static IServiceCollection AddCellSwagger(this IServiceCollection services
throw new ArgumentNullException(nameof(services));
}

var aadSettings = configuration.GetSection(AzureAdSettings.SettingsKey).Get<AzureAdSettings>();

services.AddSwaggerGen(cfg =>
{
cfg.SwaggerDoc("v1", new OpenApiInfo
Expand All @@ -31,6 +37,29 @@ public static IServiceCollection AddCellSwagger(this IServiceCollection services
Version = "v1",
Contact = new OpenApiContact { Name = "Rodolpho Alves", Url = new Uri("https://github.com/rodolphocastro/cell-cms") }
});
cfg.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Name = "Azure AD",
OpenIdConnectUrl = new Uri(aadSettings.MetadataEndpoint),
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(aadSettings.AuthorizeEndpoint),
TokenUrl = new Uri(aadSettings.TokenEndpoint),
Scopes = new Dictionary<string, string>
{
{ CellScopes.AcessoSwagger, "Permite que o usuário faça login no SwaggerUi" }
}
}
}
});
cfg.OperationFilter<SecurityRequirementsOperationFilter>();
});

return services;
Expand Down
44 changes: 44 additions & 0 deletions src/CellCms.Api/Swagger/SecurityRequirementOperationFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;

namespace CellCms.Api.Swagger
{
/// <summary>
/// Filtro para operações protegidas.
/// </summary>
/// <see cref="https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/ResourceServer/Swagger/SecurityRequirementsOperationFilter.cs"/>
public class SecurityRequirementsOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// Policy names map to scopes
var requiredScopes = context.MethodInfo
.GetCustomAttributes(true)
.OfType<AuthorizeAttribute>()
.Select(attr => attr.Policy)
.Distinct();

if (requiredScopes.Any())
{
operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });

var oAuthScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
};

operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
[ oAuthScheme ] = requiredScopes.ToList()
}
};
}
}
}
}
7 changes: 6 additions & 1 deletion src/CellCms.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"AzureAd": {
"MetadataEndpoint": "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
"AuthorizeEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token"
}
}

0 comments on commit 885280d

Please sign in to comment.