Merge changes

This commit is contained in:
Jordan Brown
2022-01-28 16:38:52 -05:00
13 changed files with 95 additions and 204 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- This is in it's own file to help incremental building, changing it causes a complete rebuild of the web panel -->
<TgsControlPanelVersion>2.4.0</TgsControlPanelVersion>
<TgsControlPanelVersion>3.0.0</TgsControlPanelVersion>
</PropertyGroup>
</Project>
+4 -1
View File
@@ -19,6 +19,9 @@ RUN . $NVM_DIR/nvm.sh \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g npm
#You may wonder why this needs to be in a seperate step. I don't know... It just works(tm)
RUN npm install -g yarn
# Build web control panel
WORKDIR /repo/build
@@ -32,7 +35,7 @@ COPY src/Tgstation.Server.Host/Tgstation.Server.Host.csproj ./
# I cant figure out how to run npm as non root so eh
RUN npm set unsafe-perm true
RUN dotnet msbuild -target:NpmBuild
RUN npm set unsafe-perm false
RUN npm set unsafe-perm fals
WORKDIR /repo
+1 -2
View File
@@ -48,8 +48,7 @@
"inconsistent_property_type": "error",
"property_case_convention": "off",
"property_case_collision": "error",
"enum_case_convention": "off",
"undefined_required_properties": "error"
"enum_case_convention": "off"
},
"walker": {
"no_empty_descriptions": "error",
+1 -1
View File
@@ -3,7 +3,7 @@
<!-- Integration tests will ensure they match across the board -->
<Import Project="ControlPanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>4.15.6</TgsCoreVersion>
<TgsCoreVersion>4.15.7</TgsCoreVersion>
<TgsConfigVersion>4.1.0</TgsConfigVersion>
<TgsApiVersion>9.3.0</TgsApiVersion>
<TgsApiLibraryVersion>9.3.1</TgsApiLibraryVersion>
+1 -1
View File
@@ -146,7 +146,7 @@ You will be granted a bearer token as in basic auth. This will have an extended
- GitHub: https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps
- Discord: https://discord.com/developers/docs/topics/oauth2
- TGForums: https://tgstation13.org/phpBB/viewtopic.php?f=45&t=9922
- TGForums: https://tgstation13.org/phpBB/viewtopic.php?f=45&t=30155
- Keycloak: https://plugins.miniorange.com/keycloak-single-sign-on-wordpress-sso-oauth-openid-connect
@section api_perms Permissions
@@ -1,103 +0,0 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.System;
namespace Tgstation.Server.Host.Security.OAuth
{
/// <summary>
/// Base <see langword="class"/> for <see cref="IOAuthValidator"/>s.
/// </summary>
abstract class BaseOAuthValidator : IOAuthValidator
{
/// <inheritdoc />
public abstract OAuthProvider Provider { get; }
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="BaseOAuthValidator"/>.
/// </summary>
protected ILogger<BaseOAuthValidator> Logger { get; }
/// <summary>
/// The <see cref="OAuthConfiguration"/> for the <see cref="BaseOAuthValidator"/>.
/// </summary>
protected OAuthConfiguration OAuthConfiguration { get; }
/// <summary>
/// The <see cref="IHttpClientFactory"/> for the <see cref="BaseOAuthValidator"/>.
/// </summary>
readonly IHttpClientFactory httpClientFactory;
/// <summary>
/// The <see cref="IAssemblyInformationProvider"/> for the <see cref="BaseOAuthValidator"/>.
/// </summary>
readonly IAssemblyInformationProvider assemblyInformationProvider;
/// <summary>
/// Gets <see cref="JsonSerializerSettings"/> that should be used.
/// </summary>
/// <returns>A new <see cref="JsonSerializerSettings"/> <see cref="object"/>.</returns>
protected static JsonSerializerSettings SerializerSettings() => new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy(),
},
};
/// <summary>
/// Initializes a new instance of the <see cref="BaseOAuthValidator"/> class.
/// </summary>
/// <param name="httpClientFactory">The value of <see cref="httpClientFactory"/>.</param>
/// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/>.</param>
/// <param name="logger">The value of <see cref="Logger"/>.</param>
/// <param name="oAuthConfiguration">The value of <see cref="OAuthConfiguration"/>.</param>
public BaseOAuthValidator(
IHttpClientFactory httpClientFactory,
IAssemblyInformationProvider assemblyInformationProvider,
ILogger<BaseOAuthValidator> logger,
OAuthConfiguration oAuthConfiguration)
{
this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
OAuthConfiguration = oAuthConfiguration ?? throw new ArgumentNullException(nameof(oAuthConfiguration));
}
/// <inheritdoc />
public abstract Task<OAuthProviderInfo> GetProviderInfo(CancellationToken cancellationToken);
/// <inheritdoc />
public abstract Task<string> ValidateResponseCode(string code, CancellationToken cancellationToken);
/// <summary>
/// Create a new configured <see cref="HttpClient"/>.
/// </summary>
/// <returns>A new configured <see cref="HttpClient"/>.</returns>
protected HttpClient CreateHttpClient()
{
var httpClient = httpClientFactory.CreateClient();
try
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
httpClient.DefaultRequestHeaders.UserAgent.Add(assemblyInformationProvider.ProductInfoHeaderValue);
return httpClient;
}
catch
{
httpClient.Dispose();
throw;
}
}
}
}
@@ -14,6 +14,15 @@ namespace Tgstation.Server.Host.Security.OAuth
/// </summary>
sealed class DiscordOAuthValidator : GenericOAuthValidator
{
/// <inheritdoc />
public override OAuthProvider Provider => OAuthProvider.Discord;
/// <inheritdoc />
protected override Uri TokenUrl => new Uri("https://discord.com/api/oauth2/token");
/// <inheritdoc />
protected override Uri UserInformationUrl => new Uri("https://discord.com/api/users/@me");
/// <summary>
/// Initializes a new instance of the <see cref="DiscordOAuthValidator"/> class.
/// </summary>
@@ -30,15 +39,6 @@ namespace Tgstation.Server.Host.Security.OAuth
{
}
/// <inheritdoc />
public override OAuthProvider Provider => OAuthProvider.Discord;
/// <inheritdoc />
protected override Uri TokenUrl => new Uri("https://discord.com/api/oauth2/token");
/// <inheritdoc />
protected override Uri UserInformationUrl => new Uri("https://discord.com/api/users/@me");
/// <inheritdoc />
protected override OAuthTokenRequest CreateTokenRequest(string code) => new OAuthTokenRequest(OAuthConfiguration, code, "identify");
@@ -2,12 +2,14 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Tgstation.Server.Api;
using Tgstation.Server.Api.Models;
@@ -19,8 +21,21 @@ namespace Tgstation.Server.Host.Security.OAuth
/// <summary>
/// <see cref="IOAuthValidator"/> for generic OAuth2 endpoints.
/// </summary>
abstract class GenericOAuthValidator : BaseOAuthValidator
abstract class GenericOAuthValidator : IOAuthValidator
{
/// <inheritdoc />
public abstract OAuthProvider Provider { get; }
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="GenericOAuthValidator"/>.
/// </summary>
protected ILogger<GenericOAuthValidator> Logger { get; }
/// <summary>
/// The <see cref="OAuthConfiguration"/> for the <see cref="GenericOAuthValidator"/>.
/// </summary>
protected OAuthConfiguration OAuthConfiguration { get; }
/// <summary>
/// <see cref="Uri"/> to <see cref="HttpMethod.Post"/> to to get the access token.
/// </summary>
@@ -31,28 +46,49 @@ namespace Tgstation.Server.Host.Security.OAuth
/// </summary>
protected abstract Uri UserInformationUrl { get; }
/// <summary>
/// The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.
/// </summary>
readonly IHttpClientFactory httpClientFactory;
/// <summary>
/// The <see cref="IAssemblyInformationProvider"/> for the <see cref="GenericOAuthValidator"/>.
/// </summary>
readonly IAssemblyInformationProvider assemblyInformationProvider;
/// <summary>
/// Gets <see cref="JsonSerializerSettings"/> that should be used.
/// </summary>
/// <returns>A new <see cref="JsonSerializerSettings"/> <see cref="object"/>.</returns>
protected static JsonSerializerSettings SerializerSettings() => new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy(),
},
};
/// <summary>
/// Initializes a new instance of the <see cref="GenericOAuthValidator"/> class.
/// </summary>
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="httpClientFactory">The value of <see cref="httpClientFactory"/>.</param>
/// <param name="assemblyInformationProvider">The value of <see cref="assemblyInformationProvider"/>.</param>
/// <param name="logger">The value of <see cref="Logger"/>.</param>
/// <param name="oAuthConfiguration">The value of <see cref="OAuthConfiguration"/>.</param>
public GenericOAuthValidator(
IHttpClientFactory httpClientFactory,
IAssemblyInformationProvider assemblyInformationProvider,
ILogger<GenericOAuthValidator> logger,
OAuthConfiguration oAuthConfiguration)
: base(
httpClientFactory,
assemblyInformationProvider,
logger,
oAuthConfiguration)
{
this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider));
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
OAuthConfiguration = oAuthConfiguration ?? throw new ArgumentNullException(nameof(oAuthConfiguration));
}
/// <inheritdoc />
public override async Task<string> ValidateResponseCode(string code, CancellationToken cancellationToken)
public async Task<string> ValidateResponseCode(string code, CancellationToken cancellationToken)
{
using var httpClient = CreateHttpClient();
string tokenResponsePayload = null;
@@ -110,7 +146,7 @@ namespace Tgstation.Server.Host.Security.OAuth
}
/// <inheritdoc />
public override Task<OAuthProviderInfo> GetProviderInfo(CancellationToken cancellationToken) => Task.FromResult(
public Task<OAuthProviderInfo> GetProviderInfo(CancellationToken cancellationToken) => Task.FromResult(
new OAuthProviderInfo
{
ClientId = OAuthConfiguration.ClientId,
@@ -138,5 +174,25 @@ namespace Tgstation.Server.Host.Security.OAuth
/// <param name="code">The OAuth code from the browser.</param>
/// <returns>The <see cref="OAuthTokenRequest"/> to send to <see cref="TokenUrl"/>.</returns>
protected abstract OAuthTokenRequest CreateTokenRequest(string code);
/// <summary>
/// Create a new configured <see cref="HttpClient"/>.
/// </summary>
/// <returns>A new configured <see cref="HttpClient"/>.</returns>
HttpClient CreateHttpClient()
{
var httpClient = httpClientFactory.CreateClient();
try
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
httpClient.DefaultRequestHeaders.UserAgent.Add(assemblyInformationProvider.ProductInfoHeaderValue);
return httpClient;
}
catch
{
httpClient.Dispose();
throw;
}
}
}
}
@@ -1,23 +0,0 @@
namespace Tgstation.Server.Host.Security.OAuth
{
/// <summary>
/// Base <see langword="class"/> for tgstation forum responses.
/// </summary>
abstract class TGBaseResponse
{
/// <summary>
/// Expected value of <see cref="Status"/>.
/// </summary>
public const string OkStatus = "OK";
/// <summary>
/// The response status.
/// </summary>
public string Status { get; set; }
/// <summary>
/// The response error, if any.
/// </summary>
public string Error { get; set; }
}
}
@@ -1,18 +0,0 @@
namespace Tgstation.Server.Host.Security.OAuth
{
/// <summary>
/// Response when creating a tgstation forums session.
/// </summary>
sealed class TGCreateSessionResponse : TGBaseResponse
{
/// <summary>
/// The session's private token. Similar to OAuth authorization response code.
/// </summary>
public string SessionPrivateToken { get; set; }
/// <summary>
/// The session's public token. Barely similar to OAuth client ID.
/// </summary>
public string SessionPublicToken { get; set; }
}
}
@@ -1,14 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Host.Configuration;
@@ -33,10 +26,10 @@ namespace Tgstation.Server.Host.Security.OAuth
/// <summary>
/// Initializes a new instance of the <see cref="TGForumsOAuthValidator"/> class.
/// </summary>
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="BaseOAuthValidator"/>.</param>
/// <param name="httpClientFactory">The <see cref="IHttpClientFactory"/> for the <see cref="GenericOAuthValidator"/>.</param>
/// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="GenericOAuthValidator"/>.</param>
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="GenericOAuthValidator"/>.</param>
/// <param name="oAuthConfiguration">The <see cref="OAuthConfiguration"/> for the <see cref="GenericOAuthValidator"/>.</param>
public TGForumsOAuthValidator(
IHttpClientFactory httpClientFactory,
IAssemblyInformationProvider assemblyInformationProvider,
@@ -51,10 +44,7 @@ namespace Tgstation.Server.Host.Security.OAuth
}
/// <inheritdoc />
protected override string DecodeTokenPayload(dynamic responseJson)
{
throw new NotImplementedException();
}
protected override string DecodeTokenPayload(dynamic responseJson) => responseJson.access_token;
/// <inheritdoc />
protected override string DecodeUserInformationPayload(dynamic responseJson) => responseJson.phpbb_username;
@@ -1,13 +0,0 @@
namespace Tgstation.Server.Host.Security.OAuth
{
/// <summary>
/// Response when getting tgstation forum user's info.
/// </summary>
sealed class TGGetSessionInfoResponse : TGBaseResponse
{
/// <summary>
/// The user's forum account name.
/// </summary>
public string PhpbbUsername { get; set; }
}
}
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="../../build/Version.props" />
<PropertyGroup>
@@ -30,14 +30,14 @@
<Message Text="Pulling web control panel..." Importance="high" />
<RemoveDir Directories="ClientApp" />
<Exec Command="git clone https://github.com/tgstation/tgstation-server-webpanel --branch v$(TgsControlPanelVersion) --depth 1 ClientApp" />
<Message Text="Restoring npm packages..." Importance="high" />
<Exec WorkingDirectory="ClientApp" Command="npm ci" />
<Message Text="Restoring yarn packages..." Importance="high" />
<Exec WorkingDirectory="ClientApp" Command="yarn install --immutable" />
<Touch Files="$(NpmInstallStampFile)" AlwaysCreate="true" />
</Target>
<Target Name="NpmBuild" BeforeTargets="BeforeBuild" DependsOnTargets="ClientInstall" Inputs="@(ClientApp)" Outputs="wwwroot\index.html">
<Message Text="Building web control panel..." Importance="high" />
<Exec WorkingDirectory="ClientApp" Command="npm run msbuild" />
<Exec WorkingDirectory="ClientApp" Command="yarn run msbuild" />
</Target>
<Target Name="NpmClean" AfterTargets="Clean">
@@ -68,7 +68,7 @@
<PackageReference Include="Cyberboss.SmartIrc4net.Standard" Version="0.4.6" />
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="1.5.3" />
<PackageReference Include="GitLabApiClient" Version="1.8.0" />
<PackageReference Include="LibGit2Sharp" Version="0.27.0-preview-0119" />
<PackageReference Include="LibGit2Sharp" Version="0.27.0-preview-0034" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.20" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.20" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3">