mirror of
https://github.com/bitwarden/server
synced 2025-12-06 00:03:34 +00:00
[BEEEP] [PM-28808] Fix invalid identity URL in Swagger (#6653)
- in generated JSON (used in help center), only show cloud options (with corrected identity URL) - in self-host and dev, only show local option
This commit is contained in:
@@ -18,11 +18,11 @@ if ($LASTEXITCODE -ne 0) {
|
|||||||
# Api internal & public
|
# Api internal & public
|
||||||
Set-Location "../../src/Api"
|
Set-Location "../../src/Api"
|
||||||
dotnet build
|
dotnet build
|
||||||
dotnet swagger tofile --output "../../api.json" --host "https://api.bitwarden.com" "./bin/Debug/net8.0/Api.dll" "internal"
|
dotnet swagger tofile --output "../../api.json" "./bin/Debug/net8.0/Api.dll" "internal"
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
||||||
}
|
}
|
||||||
dotnet swagger tofile --output "../../api.public.json" --host "https://api.bitwarden.com" "./bin/Debug/net8.0/Api.dll" "public"
|
dotnet swagger tofile --output "../../api.public.json" "./bin/Debug/net8.0/Api.dll" "public"
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
exit $LASTEXITCODE
|
exit $LASTEXITCODE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public class Startup
|
|||||||
config.Conventions.Add(new PublicApiControllersModelConvention());
|
config.Conventions.Add(new PublicApiControllersModelConvention());
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddSwagger(globalSettings, Environment);
|
services.AddSwaggerGen(globalSettings, Environment);
|
||||||
Jobs.JobsHostedService.AddJobsServices(services, globalSettings.SelfHosted);
|
Jobs.JobsHostedService.AddJobsServices(services, globalSettings.SelfHosted);
|
||||||
services.AddHostedService<Jobs.JobsHostedService>();
|
services.AddHostedService<Jobs.JobsHostedService>();
|
||||||
|
|
||||||
@@ -292,17 +292,59 @@ public class Startup
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add Swagger
|
// Add Swagger
|
||||||
|
// Note that the swagger.json generation is configured in the call to AddSwaggerGen above.
|
||||||
if (Environment.IsDevelopment() || globalSettings.SelfHosted)
|
if (Environment.IsDevelopment() || globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
|
// adds the middleware to serve the swagger.json while the server is running
|
||||||
app.UseSwagger(config =>
|
app.UseSwagger(config =>
|
||||||
{
|
{
|
||||||
config.RouteTemplate = "specs/{documentName}/swagger.json";
|
config.RouteTemplate = "specs/{documentName}/swagger.json";
|
||||||
|
|
||||||
|
// Remove all Bitwarden cloud servers and only register the local server
|
||||||
config.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
|
config.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
|
||||||
swaggerDoc.Servers = new List<OpenApiServer>
|
|
||||||
{
|
{
|
||||||
new OpenApiServer { Url = globalSettings.BaseServiceUri.Api }
|
swaggerDoc.Servers.Clear();
|
||||||
|
swaggerDoc.Servers.Add(new OpenApiServer
|
||||||
|
{
|
||||||
|
Url = globalSettings.BaseServiceUri.Api,
|
||||||
|
});
|
||||||
|
|
||||||
|
swaggerDoc.Components.SecuritySchemes.Clear();
|
||||||
|
swaggerDoc.Components.SecuritySchemes.Add("oauth2-client-credentials", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.OAuth2,
|
||||||
|
Flows = new OpenApiOAuthFlows
|
||||||
|
{
|
||||||
|
ClientCredentials = new OpenApiOAuthFlow
|
||||||
|
{
|
||||||
|
TokenUrl = new Uri($"{globalSettings.BaseServiceUri.Identity}/connect/token"),
|
||||||
|
Scopes = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ ApiScopes.ApiOrganization, "Organization APIs" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
swaggerDoc.SecurityRequirements.Clear();
|
||||||
|
swaggerDoc.SecurityRequirements.Add(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "oauth2-client-credentials"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ApiScopes.ApiOrganization]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// adds the middleware to display the web UI
|
||||||
app.UseSwaggerUI(config =>
|
app.UseSwaggerUI(config =>
|
||||||
{
|
{
|
||||||
config.DocumentTitle = "Bitwarden API Documentation";
|
config.DocumentTitle = "Bitwarden API Documentation";
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Bit.Api.AdminConsole.Authorization;
|
using Bit.Api.AdminConsole.Authorization;
|
||||||
using Bit.Api.Tools.Authorization;
|
using Bit.Api.Tools.Authorization;
|
||||||
using Bit.Core.Auth.IdentityServer;
|
|
||||||
using Bit.Core.PhishingDomainFeatures;
|
using Bit.Core.PhishingDomainFeatures;
|
||||||
using Bit.Core.PhishingDomainFeatures.Interfaces;
|
using Bit.Core.PhishingDomainFeatures.Interfaces;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
@@ -10,6 +9,7 @@ using Bit.Core.Utilities;
|
|||||||
using Bit.Core.Vault.Authorization.SecurityTasks;
|
using Bit.Core.Vault.Authorization.SecurityTasks;
|
||||||
using Bit.SharedWeb.Health;
|
using Bit.SharedWeb.Health;
|
||||||
using Bit.SharedWeb.Swagger;
|
using Bit.SharedWeb.Swagger;
|
||||||
|
using Bit.SharedWeb.Utilities;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
@@ -17,7 +17,10 @@ namespace Bit.Api.Utilities;
|
|||||||
|
|
||||||
public static class ServiceCollectionExtensions
|
public static class ServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
public static void AddSwagger(this IServiceCollection services, GlobalSettings globalSettings, IWebHostEnvironment environment)
|
/// <summary>
|
||||||
|
/// Configures the generation of swagger.json OpenAPI spec.
|
||||||
|
/// </summary>
|
||||||
|
public static void AddSwaggerGen(this IServiceCollection services, GlobalSettings globalSettings, IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
services.AddSwaggerGen(config =>
|
services.AddSwaggerGen(config =>
|
||||||
{
|
{
|
||||||
@@ -36,6 +39,8 @@ public static class ServiceCollectionExtensions
|
|||||||
organizations tools for managing members, collections, groups, event logs, and policies.
|
organizations tools for managing members, collections, groups, event logs, and policies.
|
||||||
If you are looking for the Vault Management API, refer instead to
|
If you are looking for the Vault Management API, refer instead to
|
||||||
[this document](https://bitwarden.com/help/vault-management-api/).
|
[this document](https://bitwarden.com/help/vault-management-api/).
|
||||||
|
|
||||||
|
**Note:** your authorization must match the server you have selected.
|
||||||
""",
|
""",
|
||||||
License = new OpenApiLicense
|
License = new OpenApiLicense
|
||||||
{
|
{
|
||||||
@@ -46,36 +51,20 @@ public static class ServiceCollectionExtensions
|
|||||||
|
|
||||||
config.SwaggerDoc("internal", new OpenApiInfo { Title = "Bitwarden Internal API", Version = "latest" });
|
config.SwaggerDoc("internal", new OpenApiInfo { Title = "Bitwarden Internal API", Version = "latest" });
|
||||||
|
|
||||||
config.AddSecurityDefinition("oauth2-client-credentials", new OpenApiSecurityScheme
|
// Configure Bitwarden cloud US and EU servers. These will appear in the swagger.json build artifact
|
||||||
{
|
// used for our help center. These are overwritten with the local server when running in self-hosted
|
||||||
Type = SecuritySchemeType.OAuth2,
|
// or dev mode (see Api Startup.cs).
|
||||||
Flows = new OpenApiOAuthFlows
|
config.AddSwaggerServerWithSecurity(
|
||||||
{
|
serverId: "US_server",
|
||||||
ClientCredentials = new OpenApiOAuthFlow
|
serverUrl: "https://api.bitwarden.com",
|
||||||
{
|
identityTokenUrl: "https://identity.bitwarden.com/connect/token",
|
||||||
TokenUrl = new Uri($"{globalSettings.BaseServiceUri.Identity}/connect/token"),
|
serverDescription: "US server");
|
||||||
Scopes = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ ApiScopes.ApiOrganization, "Organization APIs" },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
config.AddSecurityRequirement(new OpenApiSecurityRequirement
|
config.AddSwaggerServerWithSecurity(
|
||||||
{
|
serverId: "EU_server",
|
||||||
{
|
serverUrl: "https://api.bitwarden.eu",
|
||||||
new OpenApiSecurityScheme
|
identityTokenUrl: "https://identity.bitwarden.eu/connect/token",
|
||||||
{
|
serverDescription: "EU server");
|
||||||
Reference = new OpenApiReference
|
|
||||||
{
|
|
||||||
Type = ReferenceType.SecurityScheme,
|
|
||||||
Id = "oauth2-client-credentials"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new[] { ApiScopes.ApiOrganization }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
config.DescribeAllParametersInCamelCase();
|
config.DescribeAllParametersInCamelCase();
|
||||||
// config.UseReferencedDefinitionsForEnums();
|
// config.UseReferencedDefinitionsForEnums();
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
using NoopRepos = Bit.Core.Repositories.Noop;
|
using NoopRepos = Bit.Core.Repositories.Noop;
|
||||||
using Role = Bit.Core.Entities.Role;
|
using Role = Bit.Core.Entities.Role;
|
||||||
@@ -1067,4 +1069,61 @@ public static class ServiceCollectionExtensions
|
|||||||
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.Password) &&
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.Password) &&
|
||||||
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.EventExchangeName);
|
CoreHelpers.SettingHasValue(settings.EventLogging.RabbitMq.EventExchangeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a server with its corresponding OAuth2 client credentials security definition and requirement.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">The SwaggerGen configuration</param>
|
||||||
|
/// <param name="serverId">Unique identifier for this server (e.g., "us-server", "eu-server")</param>
|
||||||
|
/// <param name="serverUrl">The API server URL</param>
|
||||||
|
/// <param name="identityTokenUrl">The identity server token URL</param>
|
||||||
|
/// <param name="serverDescription">Human-readable description for the server</param>
|
||||||
|
public static void AddSwaggerServerWithSecurity(
|
||||||
|
this SwaggerGenOptions config,
|
||||||
|
string serverId,
|
||||||
|
string serverUrl,
|
||||||
|
string identityTokenUrl,
|
||||||
|
string serverDescription)
|
||||||
|
{
|
||||||
|
// Add server
|
||||||
|
config.AddServer(new OpenApiServer
|
||||||
|
{
|
||||||
|
Url = serverUrl,
|
||||||
|
Description = serverDescription
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add security definition
|
||||||
|
config.AddSecurityDefinition(serverId, new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.OAuth2,
|
||||||
|
Description = $"**Use this option if you've selected the {serverDescription}**",
|
||||||
|
Flows = new OpenApiOAuthFlows
|
||||||
|
{
|
||||||
|
ClientCredentials = new OpenApiOAuthFlow
|
||||||
|
{
|
||||||
|
TokenUrl = new Uri(identityTokenUrl),
|
||||||
|
Scopes = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ ApiScopes.ApiOrganization, $"Organization APIs ({serverDescription})" },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add security requirement
|
||||||
|
config.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = serverId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[ApiScopes.ApiOrganization]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user