Added classes for the Configuration

Separated the logic in domains
This commit is contained in:
Mark Ettema 2021-05-09 21:20:57 +07:00
parent e8520a6128
commit 03947fdbdc
11 changed files with 113 additions and 51 deletions

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SteamOpenIdConnectProvider.Domains.Common
{
public class HostingConfig
{
public static readonly string Key = "Hosting";
public string BasePath { get; set; }
public string PublicOrigin { get; set; }
}
}

View file

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace SteamOpenIdConnectProvider.Database namespace SteamOpenIdConnectProvider.Domains.IdentityServer
{ {
// This is completely in-memory, we do not need a persistent store. // This is completely in-memory, we do not need a persistent store.
public class AppInMemoryDbContext : IdentityDbContext<IdentityUser> public class AppInMemoryDbContext : IdentityDbContext<IdentityUser>

View file

@ -3,29 +3,30 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using IdentityServer4; using IdentityServer4;
using IdentityServer4.Models; using IdentityServer4.Models;
using SteamOpenIdConnectProvider.Domains.IdentityServer;
namespace SteamOpenIdConnectProvider namespace SteamOpenIdConnectProvider.Models.IdentityServer
{ {
public class IdentityServerConfig public static class IdentityServerConfigFactory
{ {
public static IEnumerable<Client> GetClients(string clientId, string secret, string redirectUri, string logoutRedirectUri) public static IEnumerable<Client> GetClients(OpenIdConfig config)
{ {
yield return new Client yield return new Client
{ {
ClientId = clientId, ClientId = config.ClientID,
ClientName = "Proxy Client", ClientName = config.ClientName,
AllowedGrantTypes = GrantTypes.Code, AllowedGrantTypes = GrantTypes.Code,
RequireConsent = false, RequireConsent = false,
ClientSecrets = ClientSecrets =
{ {
new Secret(secret.Sha256()) new Secret(config.ClientSecret.Sha256())
}, },
// where to redirect to after login // where to redirect to after login
RedirectUris = redirectUri.Split(",").Select(x => x.Trim()).ToArray(), RedirectUris = config.RedirectUri.Split(",").Select(x => x.Trim()).ToArray(),
// where to redirect to after logout // where to redirect to after logout
PostLogoutRedirectUris = { logoutRedirectUri }, PostLogoutRedirectUris = { config.PostLogoutRedirectUri },
RequirePkce = false, RequirePkce = false,
AllowedScopes = new List<string> AllowedScopes = new List<string>
{ {

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SteamOpenIdConnectProvider.Domains.IdentityServer
{
public class OpenIdConfig
{
public static readonly string Key = "OpenID";
public string ClientID { get; set; }
public string ClientSecret { get; set; }
public string RedirectUri { get; set; }
public string PostLogoutRedirectUri { get; set; }
public string ClientName { get; set; } = "Proxy Client";
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SteamOpenIdConnectProvider.Domains.Steam
{
public static class Constants
{
public static readonly string OpenIdUrl = "https://steamcommunity.com/openid/id/";
public static readonly string ApiUrl = "https://api.steampowered.com/";
public static readonly string GetPlayerSummariesUrl = ApiUrl + "ISteamUser/GetPlayerSummaries/v0002";
}
}

View file

@ -1,7 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using SteamOpenIdConnectProvider.Profile.Models;
namespace SteamOpenIdConnectProvider.Profile.Models namespace SteamOpenIdConnectProvider.Domains.Steam
{ {
public sealed class GetPlayerSummariesResponse public sealed class GetPlayerSummariesResponse
{ {

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SteamOpenIdConnectProvider.Domains.Steam
{
public class SteamConfig
{
public static readonly string Key = "Steam";
public string ApplicationKey { get; internal set; }
}
}

View file

@ -8,39 +8,28 @@ using IdentityServer4.Extensions;
using IdentityServer4.Models; using IdentityServer4.Models;
using IdentityServer4.Services; using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options;
using SteamOpenIdConnectProvider.Profile.Models; using SteamOpenIdConnectProvider.Domains.Steam;
using SteamOpenIdConnectProvider.Models.Steam;
namespace SteamOpenIdConnectProvider.Profile namespace SteamOpenIdConnectProvider.Services
{ {
public class SteamProfileService : IProfileService public class SteamProfileService : IProfileService
{ {
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly IConfiguration _configuration; private readonly SteamConfig _config;
private readonly IUserClaimsPrincipalFactory<IdentityUser> _claimsFactory; private readonly IUserClaimsPrincipalFactory<IdentityUser> _claimsFactory;
private readonly UserManager<IdentityUser> _userManager; private readonly UserManager<IdentityUser> _userManager;
private async Task<GetPlayerSummariesResponse> GetPlayerSummariesAsync(IEnumerable<string> steamIds)
{
const string baseurl = "https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002";
var applicationKey = _configuration["Authentication:Steam:ApplicationKey"];
var url = $"{baseurl}/?key={applicationKey}&steamids={string.Join(',', steamIds)}";
var res = await _httpClient.GetStringAsync(url);
var response = JsonSerializer.Deserialize<SteamResponse<GetPlayerSummariesResponse>>(res);
return response.Response;
}
public SteamProfileService( public SteamProfileService(
UserManager<IdentityUser> userManager, UserManager<IdentityUser> userManager,
IUserClaimsPrincipalFactory<IdentityUser> claimsFactory, IUserClaimsPrincipalFactory<IdentityUser> claimsFactory,
IConfiguration configuration, IOptions<SteamConfig> config,
HttpClient httpClient) HttpClient httpClient)
{ {
_userManager = userManager; _userManager = userManager;
_claimsFactory = claimsFactory; _claimsFactory = claimsFactory;
_configuration = configuration; _config = config.Value;
_httpClient = httpClient; _httpClient = httpClient;
} }
@ -53,8 +42,7 @@ namespace SteamOpenIdConnectProvider.Profile
var claims = principal.Claims.ToList(); var claims = principal.Claims.ToList();
claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList(); claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
const string steamUrl = "https://steamcommunity.com/openid/id/"; var steamId = sub.Substring(Constants.OpenIdUrl.Length);
var steamId = sub.Substring(steamUrl.Length);
var userSummary = await GetPlayerSummariesAsync(new[] { steamId }); var userSummary = await GetPlayerSummariesAsync(new[] { steamId });
var player = userSummary.Players.FirstOrDefault(); var player = userSummary.Players.FirstOrDefault();
@ -70,6 +58,13 @@ namespace SteamOpenIdConnectProvider.Profile
context.IssuedClaims = claims; context.IssuedClaims = claims;
} }
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
private void AddClaim(List<Claim> claims, string type, string value) private void AddClaim(List<Claim> claims, string type, string value)
{ {
if (!string.IsNullOrEmpty(value)) if (!string.IsNullOrEmpty(value))
@ -78,11 +73,12 @@ namespace SteamOpenIdConnectProvider.Profile
} }
} }
public async Task IsActiveAsync(IsActiveContext context) private async Task<GetPlayerSummariesResponse> GetPlayerSummariesAsync(IEnumerable<string> steamIds)
{ {
var sub = context.Subject.GetSubjectId(); var url = $"{Constants.GetPlayerSummariesUrl}/?key={_config.ApplicationKey}&steamids={string.Join(',', steamIds)}";
var user = await _userManager.FindByIdAsync(sub); var res = await _httpClient.GetStringAsync(url);
context.IsActive = user != null; var response = JsonSerializer.Deserialize<SteamResponse<GetPlayerSummariesResponse>>(res);
return response.Response;
} }
} }
} }

View file

@ -1,6 +1,6 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace SteamOpenIdConnectProvider.Profile.Models namespace SteamOpenIdConnectProvider.Models.Steam
{ {
public sealed class SteamResponse<T> public sealed class SteamResponse<T>
{ {

View file

@ -12,8 +12,11 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using IdentityServer4.Services; using IdentityServer4.Services;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using SteamOpenIdConnectProvider.Database; using SteamOpenIdConnectProvider.Services;
using SteamOpenIdConnectProvider.Profile; using SteamOpenIdConnectProvider.Models.IdentityServer;
using SteamOpenIdConnectProvider.Domains.Common;
using SteamOpenIdConnectProvider.Domains.IdentityServer;
using SteamOpenIdConnectProvider.Domains.Steam;
namespace SteamOpenIdConnectProvider namespace SteamOpenIdConnectProvider
{ {
@ -31,7 +34,6 @@ namespace SteamOpenIdConnectProvider
services.AddControllers() services.AddControllers()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0); .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddSingleton(Configuration);
services.AddDbContext<AppInMemoryDbContext>(options => services.AddDbContext<AppInMemoryDbContext>(options =>
options.UseInMemoryDatabase("default")); options.UseInMemoryDatabase("default"));
@ -42,21 +44,21 @@ namespace SteamOpenIdConnectProvider
.AddEntityFrameworkStores<AppInMemoryDbContext>() .AddEntityFrameworkStores<AppInMemoryDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
var openIdConfig = Configuration.GetSection(OpenIdConfig.Key).Get<OpenIdConfig>();
services.AddIdentityServer(options => services.AddIdentityServer(options =>
{ {
options.UserInteraction.LoginUrl = "/ExternalLogin"; options.UserInteraction.LoginUrl = "/ExternalLogin";
}) })
.AddAspNetIdentity<IdentityUser>() .AddAspNetIdentity<IdentityUser>()
.AddInMemoryClients(IdentityServerConfig.GetClients( .AddInMemoryClients(IdentityServerConfigFactory.GetClients(openIdConfig))
Configuration["OpenID:ClientID"],
Configuration["OpenID:ClientSecret"],
Configuration["OpenID:RedirectUri"],
Configuration["OpenID:PostLogoutRedirectUri"]))
.AddInMemoryPersistedGrants() .AddInMemoryPersistedGrants()
.AddDeveloperSigningCredential(true) .AddDeveloperSigningCredential(true)
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources()); .AddInMemoryIdentityResources(IdentityServerConfigFactory.GetIdentityResources());
services.AddHttpClient<IProfileService, SteamProfileService>(); var steamConfig = Configuration.GetSection(SteamConfig.Key).Get<SteamConfig>();
services
.Configure<SteamConfig>(Configuration.GetSection(SteamConfig.Key))
.AddHttpClient<IProfileService, SteamProfileService>();
services.AddAuthentication() services.AddAuthentication()
.AddCookie(options => .AddCookie(options =>
@ -66,7 +68,7 @@ namespace SteamOpenIdConnectProvider
}) })
.AddSteam(options => .AddSteam(options =>
{ {
options.ApplicationKey = Configuration["Authentication:Steam:ApplicationKey"]; options.ApplicationKey = steamConfig.ApplicationKey;
}); });
services.AddHealthChecks() services.AddHealthChecks()
@ -80,18 +82,18 @@ namespace SteamOpenIdConnectProvider
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
} }
if (!string.IsNullOrEmpty(Configuration["Hosting:PathBase"])) var hostingConfig = Configuration.GetSection(HostingConfig.Key).Get<HostingConfig>();
if (!string.IsNullOrEmpty(hostingConfig.BasePath))
{ {
app.UsePathBase(Configuration["Hosting:PathBase"]); app.UsePathBase(hostingConfig.BasePath);
} }
app.UseCookiePolicy(); app.UseCookiePolicy();
app.Use(async (ctx, next) => app.Use(async (ctx, next) =>
{ {
var origin = Configuration["Hosting:PublicOrigin"]; if (!string.IsNullOrEmpty(hostingConfig.PublicOrigin))
if (!string.IsNullOrEmpty(origin))
{ {
ctx.SetIdentityServerOrigin(origin); ctx.SetIdentityServerOrigin(hostingConfig.PublicOrigin);
} }
await next(); await next();