@@ -1251,7 +1251,393 @@ For additional information, see the updated [Security documentation](../security
12511251The CredHub client has been removed from Steeltoe in v4.
12521252Use [ CredHub Service Broker] ( https://techdocs.broadcom.com/us/en/vmware-tanzu/platform-services/credhub-service-broker/services/credhub-sb/index.html ) instead.
12531253
1254- ### TODO: JWT/OAuth/OpenID Connect/Certificates...
1254+ ### OAuth
1255+
1256+ OAuth support has been removed from Steeltoe in v4. Use OpenID Connect instead.
1257+
1258+ Before migrating to Steeltoe v4, apply the following changes to migrate from OAuth to OpenID Connect using Steeltoe v3.
1259+
1260+ appsettings.json:
1261+
1262+ ``` diff
1263+ {
1264+ "$schema": "https://steeltoe.io/schema/v3/schema.json",
1265+ "Security": {
1266+ "Oauth2": {
1267+ "Client": {
1268+ - "AuthDomain": "http://localhost:8080",
1269+ + "Authority": "http://localhost:8080",
1270+ + "MetadataAddress": "http://localhost:8080/.well-known/openid-configuration",
1271+ + "RequireHttpsMetadata": false,
1272+ + "AdditionalScopes": "sampleapi.read",
1273+ "CallbackPath": "/signin-oidc",
1274+ "ClientId": "steeltoesamplesclient",
1275+ "ClientSecret": "client_secret"
1276+ }
1277+ }
1278+ }
1279+ }
1280+ ```
1281+
1282+ > [ !NOTE]
1283+ > Depending on your application's needs, you may need to add scopes to the application's configuration that did not previously need to be specified.
1284+
1285+ program.cs:
1286+
1287+ ``` diff
1288+ using Microsoft.AspNetCore.Authentication.Cookies;
1289+ using Microsoft.AspNetCore.HttpOverrides;
1290+ using Steeltoe.Extensions.Configuration.CloudFoundry;
1291+ using Steeltoe.Security.Authentication.CloudFoundry;
1292+
1293+ var builder = WebApplication.CreateBuilder(args);
1294+ builder.AddCloudFoundryConfiguration();
1295+ builder.Services.AddAuthentication(options =>
1296+ {
1297+ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
1298+ options.DefaultChallengeScheme = CloudFoundryDefaults.AuthenticationScheme;
1299+ })
1300+ .AddCookie(options => options.AccessDeniedPath = new PathString("/Home/AccessDenied"))
1301+ - .AddCloudFoundryOAuth(builder.Configuration);
1302+ + .AddCloudFoundryOpenIdConnect(builder.Configuration);
1303+ builder.Services.AddAuthorizationBuilder()
1304+ .AddPolicy("read", policy => policy.RequireClaim("scope", "sampleapi.read"));
1305+
1306+ var app = builder.Build();
1307+
1308+ app.UseForwardedHeaders(new ForwardedHeadersOptions
1309+ {
1310+ ForwardedHeaders = ForwardedHeaders.XForwardedProto
1311+ });
1312+
1313+ app.UseAuthentication();
1314+ app.UseAuthorization();
1315+
1316+ app.MapGet("/test-auth", async httpContext =>
1317+ {
1318+ httpContext.Response.StatusCode = 200;
1319+ httpContext.Response.ContentType = "text/plain";
1320+ await httpContext.Response.WriteAsync("You are logged in and carry the required claim.");
1321+ }).RequireAuthorization("read");
1322+
1323+ app.Run();
1324+ ```
1325+
1326+ ### OpenID Connect
1327+
1328+ Project file:
1329+
1330+ ``` diff
1331+ <Project>
1332+ <ItemGroup>
1333+ - <PackageReference Include="Steeltoe.Extensions.Configuration.CloudFoundryCore" Version="3.*" />
1334+ + <PackageReference Include="Steeltoe.Configuration.CloudFoundry" Version="4.0.0" />
1335+ - <PackageReference Include="Steeltoe.Security.Authentication.CloudFoundryCore" Version="3.*" />
1336+ + <PackageReference Include="Steeltoe.Security.Authentication.OpenIdConnect" Version="4.0.0" />
1337+ </ItemGroup>
1338+ </Project>
1339+ ```
1340+
1341+ appsettings.json:
1342+
1343+ ``` diff
1344+ {
1345+ - "$schema": "https://steeltoe.io/schema/v3/schema.json",
1346+ + "$schema": "https://steeltoe.io/schema/v4/schema.json",
1347+ - "Security": {
1348+ - "Oauth2": {
1349+ - "Client": {
1350+ - "Authority": "http://localhost:8080",
1351+ - "MetadataAddress": "http://localhost:8080/.well-known/openid-configuration",
1352+ - "RequireHttpsMetadata": false,
1353+ - "AdditionalScopes": "sampleapi.read",
1354+ - "CallbackPath": "/signin-oidc",
1355+ - "ClientId": "steeltoesamplesclient",
1356+ - "ClientSecret": "client_secret"
1357+ - }
1358+ - }
1359+ - }
1360+ + "Authentication": {
1361+ + "Schemes": {
1362+ + "OpenIdConnect": {
1363+ + "Authority": "http://localhost:8080",
1364+ + "MetadataAddress": "http://localhost:8080/.well-known/openid-configuration",
1365+ + "RequireHttpsMetadata": false,
1366+ + "Scope": [ "openid", "sampleapi.read" ],
1367+ + "CallbackPath": "/signin-oidc",
1368+ + "ClientId": "steeltoesamplesclient",
1369+ + "ClientSecret": "client_secret"
1370+ + }
1371+ + }
1372+ + }
1373+ }
1374+ ```
1375+
1376+ > [ !NOTE]
1377+ > This is not a complete listing of appsettings. As of version 4, Steeltoe configures Microsoft's option class rather than maintaining separate options.
1378+ > Refer to [ the OpenIdConnectOptions class documentation] ( https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.authentication.openidconnect.openidconnectoptions ) for the new options.
1379+
1380+ Program.cs:
1381+
1382+ ``` diff
1383+ using Microsoft.AspNetCore.Authentication.Cookies;
1384+ - using Microsoft.AspNetCore.HttpOverrides;
1385+ - using Steeltoe.Extensions.Configuration.CloudFoundry;
1386+ + using Steeltoe.Configuration.CloudFoundry;
1387+ + using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
1388+ - using Steeltoe.Security.Authentication.CloudFoundry;
1389+ + using Microsoft.AspNetCore.Authentication.OpenIdConnect;
1390+ + using Steeltoe.Security.Authentication.OpenIdConnect;
1391+
1392+ var builder = WebApplication.CreateBuilder(args);
1393+ builder.AddCloudFoundryConfiguration();
1394+ + builder.Configuration.AddCloudFoundryServiceBindings();
1395+ builder.Services.AddAuthentication(options =>
1396+ {
1397+ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
1398+ - options.DefaultChallengeScheme = CloudFoundryDefaults.AuthenticationScheme;
1399+ + options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
1400+ })
1401+ .AddCookie(options => options.AccessDeniedPath = new PathString("/Home/AccessDenied"))
1402+ - .AddCloudFoundryOpenIdConnect(builder.Configuration);
1403+ + .AddOpenIdConnect().ConfigureOpenIdConnectForCloudFoundry();
1404+ builder.Services.AddAuthorizationBuilder()
1405+ .AddPolicy("read", policy => policy.RequireClaim("scope", "sampleapi.read"));
1406+
1407+ var app = builder.Build();
1408+
1409+ - app.UseForwardedHeaders(new ForwardedHeadersOptions
1410+ - {
1411+ - ForwardedHeaders = ForwardedHeaders.XForwardedProto
1412+ - });
1413+
1414+ app.UseAuthentication();
1415+ app.UseAuthorization();
1416+
1417+ app.MapGet("/test-auth", async httpContext =>
1418+ {
1419+ httpContext.Response.StatusCode = 200;
1420+ httpContext.Response.ContentType = "text/plain";
1421+ await httpContext.Response.WriteAsync("You are logged in and carry the required claim.");
1422+ }).RequireAuthorization("read");
1423+
1424+ app.Run();
1425+ ```
1426+
1427+ ### JWT Bearer
1428+
1429+ Project file:
1430+
1431+ ``` diff
1432+ <Project>
1433+ <ItemGroup>
1434+ - <PackageReference Include="Steeltoe.Extensions.Configuration.CloudFoundryCore" Version="3.*" />
1435+ + <PackageReference Include="Steeltoe.Configuration.CloudFoundry" Version="4.0.0" />
1436+ - <PackageReference Include="Steeltoe.Security.Authentication.CloudFoundryCore" Version="3.*" />
1437+ + <PackageReference Include="Steeltoe.Security.Authentication.JwtBearer" Version="4.0.0" />
1438+ </ItemGroup>
1439+ </Project>
1440+ ```
1441+
1442+ appsettings.json:
1443+
1444+ ``` diff
1445+ {
1446+ - "$schema": "https://steeltoe.io/schema/v3/schema.json",
1447+ + "$schema": "https://steeltoe.io/schema/v4/schema.json",
1448+ - "Security": {
1449+ - "Oauth2": {
1450+ - "Client": {
1451+ - "AuthDomain": "http://localhost:8080",
1452+ - "MetadataAddress": "http://localhost:8080/.well-known/openid-configuration",
1453+ - "RequireHttpsMetadata": false,
1454+ - "ClientId": "steeltoesamplesserver",
1455+ - "ClientSecret": "server_secret"
1456+ - }
1457+ - }
1458+ - }
1459+ + "Authentication": {
1460+ + "Schemes": {
1461+ + "Bearer": {
1462+ + "Authority": "http://localhost:8080",
1463+ + "MetadataAddress": "http://localhost:8080/.well-known/openid-configuration",
1464+ + "RequireHttpsMetadata": false,
1465+ + "ClientId": "steeltoesamplesserver",
1466+ + "ClientSecret": "server_secret",
1467+ + "ValidAudiences": [ "sampleapi" ]
1468+ + }
1469+ + }
1470+ + }
1471+ }
1472+ ```
1473+
1474+ > [ !NOTE]
1475+ > This is not a complete listing of appsettings. As of version 4, Steeltoe configures Microsoft's option class rather than maintaining separate options.
1476+ > Refer to [ the JwtBearerOptions class documentation] ( https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbeareroptions ) for the new options.
1477+
1478+ Program.cs:
1479+
1480+ ``` diff
1481+ - using Microsoft.AspNetCore.HttpOverrides;
1482+ - using Steeltoe.Extensions.Configuration.CloudFoundry;
1483+ + using Steeltoe.Configuration.CloudFoundry;
1484+ + using Steeltoe.Configuration.CloudFoundry.ServiceBindings;
1485+ - using Steeltoe.Security.Authentication.CloudFoundry;
1486+ + using Steeltoe.Security.Authentication.JwtBearer;
1487+
1488+ var builder = WebApplication.CreateBuilder(args);
1489+
1490+ builder.AddCloudFoundryConfiguration();
1491+ + builder.Configuration.AddCloudFoundryServiceBindings();
1492+ builder.Services.AddAuthentication()
1493+ - .AddCloudFoundryJwtBearer(builder.Configuration);
1494+ + .AddJwtBearer().ConfigureJwtBearerForCloudFoundry();
1495+ builder.Services.AddAuthorizationBuilder()
1496+ .AddPolicy("sampleapi.read", policy => policy.RequireClaim("scope", "sampleapi.read"));
1497+
1498+ var app = builder.Build();
1499+
1500+ - app.UseForwardedHeaders(new ForwardedHeadersOptions
1501+ - {
1502+ - ForwardedHeaders = ForwardedHeaders.XForwardedProto
1503+ - });
1504+
1505+ app.UseAuthentication();
1506+ app.UseAuthorization();
1507+
1508+ app.MapGet("/test-jwt", async httpContext =>
1509+ {
1510+ httpContext.Response.StatusCode = 200;
1511+ httpContext.Response.ContentType = "text/plain";
1512+ await httpContext.Response.WriteAsync("JWT is valid and contains the required claim.");
1513+ }).RequireAuthorization("sampleapi.read");
1514+
1515+ app.Run();
1516+ ```
1517+
1518+ ### Client Certificates (Mutual TLS)
1519+
1520+ Project file:
1521+
1522+ ``` diff
1523+ <Project>
1524+ <ItemGroup>
1525+ - <PackageReference Include="Steeltoe.Security.Authentication.CloudFoundryCore" Version="3.*" />
1526+ + <PackageReference Include="Steeltoe.Security.Authorization.Certificate" Version="4.0.0" />
1527+ </ItemGroup>
1528+ </Project>
1529+ ```
1530+
1531+ launchsettings.json (server-side):
1532+
1533+ ``` diff
1534+ {
1535+ "profiles": {
1536+ "http": {
1537+ "commandName": "Project",
1538+ "applicationUrl": "https://localhost:7107"
1539+ }
1540+ }
1541+ }
1542+ ```
1543+
1544+ Program.cs (server-side):
1545+
1546+ ``` diff
1547+ + using Steeltoe.Common.Certificates;
1548+ - using Steeltoe.Security.Authentication.CloudFoundry;
1549+ + using Steeltoe.Security.Authorization.Certificate;
1550+
1551+ const string orgId = "a8fef16f-94c0-49e3-aa0b-ced7c3da6229";
1552+ const string spaceId = "122b942a-d7b9-4839-b26e-836654b9785f";
1553+
1554+ var builder = WebApplication.CreateBuilder(args);
1555+ - builder.Configuration.AddCloudFoundryContainerIdentity(orgId, spaceId);
1556+ + builder.Configuration.AddAppInstanceIdentityCertificate(new Guid(orgId), new Guid(spaceId));
1557+ - builder.Services.AddCloudFoundryCertificateAuth(options => options.CertificateHeader = "X-Forwarded-Client-Cert");
1558+ + builder.Services.AddAuthentication().AddCertificate();
1559+ + builder.Services.AddAuthorizationBuilder().AddOrgAndSpacePolicies("X-Forwarded-Client-Cert");
1560+
1561+ var app = builder.Build();
1562+
1563+ - app.UseCloudFoundryCertificateAuth();
1564+ + app.UseCertificateAuthorization();
1565+
1566+ app.MapGet("/test-same-org", async httpContext =>
1567+ {
1568+ httpContext.Response.StatusCode = 200;
1569+ httpContext.Response.ContentType = "text/plain";
1570+ await httpContext.Response.WriteAsync("Client and server identity certificates have matching Org values.");
1571+ })
1572+ - .RequireAuthorization(CloudFoundryDefaults.SameOrganizationAuthorizationPolicy);
1573+ + .RequireAuthorization(CertificateAuthorizationPolicies.SameOrg);
1574+ app.MapGet("/test-same-space", async httpContext =>
1575+ {
1576+ httpContext.Response.StatusCode = 200;
1577+ httpContext.Response.ContentType = "text/plain";
1578+ await httpContext.Response.WriteAsync("Client and server identity certificates have matching Space values.");
1579+ })
1580+ - .RequireAuthorization(CloudFoundryDefaults.SameSpaceAuthorizationPolicy);
1581+ + .RequireAuthorization(CertificateAuthorizationPolicies.SameSpace);
1582+
1583+ app.Run();
1584+ ```
1585+
1586+ > [ !NOTE]
1587+ > Prior to Steeltoe 3.3.0, Steeltoe Certificate Auth used the header ` X-Forwarded-Client-Cert ` , which was not configurable.
1588+ > The code shown above is provided for compatibility between the versions. The preferred header name is ` X-Client-Cert ` .
1589+ > In Steeltoe 4.0, the default header is ` X-Client-Cert ` , so the parameter can be omitted if cross-compatibility is not required.
1590+
1591+ Program.cs (client-side):
1592+
1593+ ``` diff
1594+ - using System.Security.Cryptography.X509Certificates;
1595+ - using Microsoft.Extensions.Options;
1596+ - using Steeltoe.Common.Options;
1597+ + using Steeltoe.Common.Certificates;
1598+ - using Steeltoe.Security.Authentication.CloudFoundry;
1599+ + using Steeltoe.Security.Authorization.Certificate;
1600+
1601+ const string orgId = "a8fef16f-94c0-49e3-aa0b-ced7c3da6229";
1602+ const string spaceId = "122b942a-d7b9-4839-b26e-836654b9785f";
1603+
1604+ var builder = WebApplication.CreateBuilder(args);
1605+
1606+ - builder.Configuration.AddCloudFoundryContainerIdentity(orgId, spaceId);
1607+ + builder.Configuration.AddAppInstanceIdentityCertificate(new Guid(orgId), new Guid(spaceId));
1608+ - builder.Services.AddCloudFoundryContainerIdentity();
1609+ builder.Services
1610+ - .AddHttpClient<TestClient>((services, client) =>
1611+ - {
1612+ - client.BaseAddress = new Uri("https://localhost:7107");
1613+ - var options = services.GetRequiredService<IOptions<CertificateOptions>>();
1614+ - var b64 = Convert.ToBase64String(options.Value.Certificate.Export(X509ContentType.Cert));
1615+ - client.DefaultRequestHeaders.Add("X-Forwarded-Client-Cert", b64);
1616+ - });
1617+ + .AddHttpClient<TestClient>(httpClient => httpClient.BaseAddress = new Uri("https://localhost:7107"))
1618+ + .AddAppInstanceIdentityCertificate("X-Forwarded-Client-Cert");
1619+
1620+ var app = builder.Build();
1621+
1622+ var testClient = app.Services.GetRequiredService<TestClient>();
1623+ string orgResponse = await testClient.GetAsync("/test-same-org");
1624+ Console.WriteLine($"Org response: {orgResponse}");
1625+ string spaceResponse = await testClient.GetAsync("/test-same-space");
1626+ Console.WriteLine($"Space response: {spaceResponse}");
1627+
1628+ public class TestClient(HttpClient httpClient)
1629+ {
1630+ public async Task<string> GetAsync(string requestPath)
1631+ {
1632+ return await httpClient.GetStringAsync(requestPath);
1633+ }
1634+ }
1635+ ```
1636+
1637+ > [ !NOTE]
1638+ > Prior to Steeltoe 3.3.0, Steeltoe Certificate Auth used the header ` X-Forwarded-Client-Cert ` , which was not configurable.
1639+ > The code shown above is provided for compatibility between the versions. The preferred header name is ` X-Client-Cert ` .
1640+ > In Steeltoe 4.0, the default header is ` X-Client-Cert ` , so the parameter can be omitted if cross-compatibility is not required.
12551641
12561642### DataProtection Key Store using Redis/Valkey
12571643
0 commit comments