Skip to content

Commit

Permalink
Add fallback to OIDC discovery for swagger ui
Browse files Browse the repository at this point in the history
  • Loading branch information
domi-b committed Aug 29, 2024
1 parent bfaea7a commit 6cdb12f
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 48 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,20 @@ In der [Entwicklungsumgebung](./config/realms/keycloak-geopilot.json) wird die A

### Appsettings

Folgende Appsettings müssen definiert sein (Beispiel aus [appsettings.Development.json](./src/Geopilot.Api/appsettings.Development.json) für die Entwicklungsumgebung):
Folgende Appsettings können definiert werden (Beispiel aus [appsettings.Development.json](./src/Geopilot.Api/appsettings.Development.json) für die Entwicklungsumgebung):

```json5
"Auth": {
// General auth options
"Authority": "http://localhost:4011/realms/geopilot", // Token issuer
"ClientId": "geopilot-client", // Token audience
"Authority": "http://localhost:4011/realms/geopilot", // Token issuer (required)
"ClientId": "geopilot-client", // Token audience (required)

// Swagger UI auth options
"ApiOrigin": "https://localhost:7188", // Swagger UI origin (required)
"AuthorizationUrl": "http://localhost:4011/realms/geopilot/protocol/openid-connect/auth", // OAuth2 login URL
"TokenUrl": "http://localhost:4011/realms/geopilot/protocol/openid-connect/token", // OAuth2 token URL
"ApiScope": "<custom app scope> (optional)",
"ApiOrigin": "https://localhost:7188" // Swagger UI origin
"ApiScope": "<custom app scope>"
}
```

Falls die `AuthorizationUrl` und/oder `TokenUrl` nicht definiert sind, wird im Swagger UI die OpenID Konfiguration der Authority (`<authority-url>/.well-known/openid-configuration`) geladen und alle vom Identity Provider unterstützten Flows angezeigt.
52 changes: 9 additions & 43 deletions src/Geopilot.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,52 +103,18 @@
// Workaround for STAC API having multiple actions mapped to the "search" route.
options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());

var scopes = new Dictionary<string, string>
var authUrl = builder.Configuration["Auth:AuthorizationUrl"];
var tokenUrl = builder.Configuration["Auth:TokenUrl"];
if (!string.IsNullOrEmpty(authUrl) && !string.IsNullOrEmpty(tokenUrl))
{
{ "openid", "Open Id" },
{ "email", "User Email" },
{ "profile", "User Profile" },
};
var apiScope = builder.Configuration["Auth:ApiScope"];
if (apiScope != null)
{
scopes.Add(apiScope, "geopilot API (required)");
var apiScope = builder.Configuration["Auth:ApiScope"];
options.AddGeopilotOAuth2(authUrl, tokenUrl, apiScope);
}

options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
{
Name = "Authorization",
Scheme = JwtBearerDefaults.AuthenticationScheme,
In = ParameterLocation.Header,
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
Scopes = scopes,
AuthorizationUrl = new Uri(builder.Configuration["Auth:AuthorizationUrl"] !),
TokenUrl = new Uri(builder.Configuration["Auth:TokenUrl"] !),
RefreshUrl = new Uri(builder.Configuration["Auth:TokenUrl"] !),
},
},
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
else
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = JwtBearerDefaults.AuthenticationScheme,
},
Scheme = "oauth2",
Name = JwtBearerDefaults.AuthenticationScheme,
In = ParameterLocation.Header,
},
Array.Empty<string>()
},
});
var authority = builder.Configuration["Auth:Authority"];
options.AddOpenIdConnect(authority!);
}
});

builder.Services
Expand Down
96 changes: 96 additions & 0 deletions src/Geopilot.Api/SwaggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Geopilot.Api;

/// <summary>
/// Provides extension methods related to Swagger.
/// </summary>
public static class SwaggerExtensions
{
private const string SchemeName = "Authorization";

/// <summary>
/// Adds a security definition and requirement for OpenId Connect using the well-known configuration of the <paramref name="authority"/>.
/// </summary>
/// <param name="options">The swagger options.</param>
/// <param name="authority">The authority and token issuer.</param>
public static void AddOpenIdConnect(this SwaggerGenOptions options, string authority)
{
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
{
Name = SchemeName,
Scheme = JwtBearerDefaults.AuthenticationScheme,
In = ParameterLocation.Header,
Type = SecuritySchemeType.OpenIdConnect,
OpenIdConnectUrl = new Uri($"{authority}/.well-known/openid-configuration"),
});
options.AddOAuth2SecurityRequirement();
}

/// <summary>
/// Adds a security definition and requirement for OAuth2 authorization code flow.
/// </summary>
/// <param name="options">The swagger options.</param>
/// <param name="authUrl">The authorization URL.</param>
/// <param name="tokenUrl">The token URL.</param>
/// <param name="apiScope">An optional scope defined for the client.</param>
public static void AddGeopilotOAuth2(this SwaggerGenOptions options, string authUrl, string tokenUrl, string? apiScope)
{
var scopes = new Dictionary<string, string>
{
{ "openid", "Open Id" },
{ "email", "User Email" },
{ "profile", "User Profile" },
};
if (apiScope != null)
{
scopes.Add(apiScope, "geopilot API (required)");
}

options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme
{
Name = SchemeName,
Scheme = JwtBearerDefaults.AuthenticationScheme,
In = ParameterLocation.Header,
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
Scopes = scopes,
AuthorizationUrl = new Uri(authUrl),
TokenUrl = new Uri(tokenUrl),
RefreshUrl = new Uri(tokenUrl),
},
},
});
options.AddOAuth2SecurityRequirement();
}

/// <summary>
/// Adds a security requirement for OAuth2.
/// </summary>
/// <param name="options">The swagger options.</param>
private static void AddOAuth2SecurityRequirement(this SwaggerGenOptions options)
{
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = JwtBearerDefaults.AuthenticationScheme,
},
Scheme = "oauth2",
Name = JwtBearerDefaults.AuthenticationScheme,
In = ParameterLocation.Header,
},
Array.Empty<string>()
},
});
}
}

0 comments on commit 6cdb12f

Please sign in to comment.