From 1c71af47bb0bfd732ad9c49007ccd97cd89e0e2c Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 28 Feb 2019 14:20:14 -0500 Subject: [PATCH] swagger specs for public api --- src/Api/Api.csproj | 5 +++ src/Api/Startup.cs | 19 ++++++++++ .../Utilities/ApiExplorerGroupConvention.cs | 13 +++++++ .../Utilities/ServiceCollectionExtensions.cs | 35 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 src/Api/Utilities/ApiExplorerGroupConvention.cs create mode 100644 src/Api/Utilities/ServiceCollectionExtensions.cs diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index 44e91565ad..a9e60ac9f0 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -14,6 +14,11 @@ + + + + + diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs index f23015cd3e..316d344f0c 100644 --- a/src/Api/Startup.cs +++ b/src/Api/Startup.cs @@ -14,6 +14,7 @@ using Stripe; using Bit.Core.Utilities; using IdentityModel; using Microsoft.AspNetCore.HttpOverrides; +using Swashbuckle.AspNetCore.Swagger; namespace Bit.Api { @@ -110,10 +111,13 @@ namespace Bit.Api // MVC services.AddMvc(config => { + config.Conventions.Add(new ApiExplorerGroupConvention()); config.Filters.Add(new ExceptionHandlerFilterAttribute()); config.Filters.Add(new ModelStateValidationFilterAttribute()); }).AddJsonOptions(o => o.SerializerSettings.ContractResolver = new DefaultContractResolver()); + services.AddSwagger(globalSettings); + if(globalSettings.SelfHosted) { // Jobs service @@ -182,6 +186,21 @@ namespace Bit.Api // Add MVC to the request pipeline. app.UseMvc(); + + if(globalSettings.SelfHosted) + { + app.UseSwagger(config => + { + config.RouteTemplate = "specs/{documentName}/swagger.json"; + }); + app.UseSwaggerUI(config => + { + config.RoutePrefix = "docs"; + config.SwaggerEndpoint("/specs/public/swagger.json", "Bitwarden Public API"); + config.OAuthClientId("accountType.id"); + config.OAuthClientSecret("secretKey"); + }); + } } } } diff --git a/src/Api/Utilities/ApiExplorerGroupConvention.cs b/src/Api/Utilities/ApiExplorerGroupConvention.cs new file mode 100644 index 0000000000..5b8d7559ae --- /dev/null +++ b/src/Api/Utilities/ApiExplorerGroupConvention.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace Bit.Api.Utilities +{ + public class ApiExplorerGroupConvention : IControllerModelConvention + { + public void Apply(ControllerModel controller) + { + var controllerNamespace = controller.ControllerType.Namespace; + controller.ApiExplorer.GroupName = controllerNamespace.Contains(".Public.") ? "public" : "internal"; + } + } +} diff --git a/src/Api/Utilities/ServiceCollectionExtensions.cs b/src/Api/Utilities/ServiceCollectionExtensions.cs new file mode 100644 index 0000000000..492b926ddf --- /dev/null +++ b/src/Api/Utilities/ServiceCollectionExtensions.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Bit.Core; +using Microsoft.Extensions.DependencyInjection; +using Swashbuckle.AspNetCore.Swagger; + +namespace Bit.Api.Utilities +{ + public static class ServiceCollectionExtensions + { + public static void AddSwagger(this IServiceCollection services, GlobalSettings globalSettings) + { + services.AddSwaggerGen(config => + { + config.SwaggerDoc("public", new Info { Title = "Bitwarden Public API", Version = "latest" }); + // config.SwaggerDoc("internal", new Info { Title = "Bitwarden Internal API", Version = "latest" }); + + config.AddSecurityDefinition("OAuth2 Client Credentials", new OAuth2Scheme + { + Type = "oauth2", + Flow = "application", + TokenUrl = $"{globalSettings.BaseServiceUri.Identity}/connect/token", + Scopes = new Dictionary + { + { "api.organization", "Organization APIs" }, + }, + }); + + config.AddSecurityRequirement(new Dictionary> + { + { "OAuth2 Client Credentials", new[] { "api.organization" } } + }); + }); + } + } +}