tgstation-server 5.12.7
The /tg/station 13 server suite
Loading...
Searching...
No Matches
GenericOAuthValidator.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Net.Http;
4using System.Net.Http.Headers;
5using System.Net.Mime;
6using System.Threading;
7using System.Threading.Tasks;
8
9using Microsoft.Extensions.Logging;
10using Newtonsoft.Json;
11using Newtonsoft.Json.Linq;
12using Newtonsoft.Json.Serialization;
13
18
20{
25 {
27 public abstract OAuthProvider Provider { get; }
28
32 protected ILogger<GenericOAuthValidator> Logger { get; }
33
38
42 protected abstract Uri TokenUrl { get; }
43
47 protected abstract Uri UserInformationUrl { get; }
48
53
58 protected static JsonSerializerSettings SerializerSettings() => new ()
59 {
60 ContractResolver = new DefaultContractResolver
61 {
62 NamingStrategy = new SnakeCaseNamingStrategy(),
63 },
64 };
65
74 ILogger<GenericOAuthValidator> logger,
75 OAuthConfiguration oAuthConfiguration)
76 {
77 this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
78 Logger = logger ?? throw new ArgumentNullException(nameof(logger));
79 OAuthConfiguration = oAuthConfiguration ?? throw new ArgumentNullException(nameof(oAuthConfiguration));
80 }
81
83 public async Task<string> ValidateResponseCode(string code, CancellationToken cancellationToken)
84 {
85 using var httpClient = CreateHttpClient();
86 string tokenResponsePayload = null;
87 string userInformationPayload = null;
88 try
89 {
90 Logger.LogTrace("Validating response code...");
91 using var tokenRequest = new HttpRequestMessage(HttpMethod.Post, TokenUrl);
92
93 var tokenRequestPayload = CreateTokenRequest(code);
94
95 // roundabout but it works
96 var tokenRequestJson = JsonConvert.SerializeObject(
97 tokenRequestPayload,
99
100 var tokenRequestDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(tokenRequestJson);
101 tokenRequest.Content = new FormUrlEncodedContent(tokenRequestDictionary);
102
103 using var tokenResponse = await httpClient.SendAsync(tokenRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
104 tokenResponse.EnsureSuccessStatusCode();
105 tokenResponsePayload = await tokenResponse.Content.ReadAsStringAsync(cancellationToken);
106 var tokenResponseJson = JObject.Parse(tokenResponsePayload);
107
108 var accessToken = DecodeTokenPayload(tokenResponseJson);
109 if (accessToken == null)
110 {
111 Logger.LogTrace("No token from DecodeTokenPayload!");
112 return null;
113 }
114
115 Logger.LogTrace("Getting user details...");
116
118 using var userInformationRequest = new HttpRequestMessage(HttpMethod.Get, userInfoUrl);
119 userInformationRequest.Headers.Authorization = new AuthenticationHeaderValue(
121 accessToken);
122
123 using var userInformationResponse = await httpClient.SendAsync(userInformationRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
124 userInformationResponse.EnsureSuccessStatusCode();
125 userInformationPayload = await userInformationResponse.Content.ReadAsStringAsync(cancellationToken);
126
127 var userInformationJson = JObject.Parse(userInformationPayload);
128
129 return DecodeUserInformationPayload(userInformationJson);
130 }
131 catch (Exception ex)
132 {
133 Logger.LogWarning(
134 ex,
135 "Error while completing OAuth handshake! Payload:{newLine}{responsePayload}",
136 Environment.NewLine,
137 userInformationPayload ?? tokenResponsePayload);
138 return null;
139 }
140 }
141
143 public Task<OAuthProviderInfo> GetProviderInfo(CancellationToken cancellationToken) => Task.FromResult(
145 {
146 ClientId = OAuthConfiguration.ClientId,
147 RedirectUri = OAuthConfiguration.RedirectUrl,
148 ServerUrl = OAuthConfiguration.ServerUrl,
149 });
150
156 protected abstract string DecodeTokenPayload(dynamic responseJson);
157
163 protected abstract string DecodeUserInformationPayload(dynamic responseJson);
164
170 protected abstract OAuthTokenRequest CreateTokenRequest(string code);
171
177 {
178 var httpClient = httpClientFactory.CreateClient();
179 try
180 {
181 httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
182 return httpClient;
183 }
184 catch
185 {
186 httpClient.Dispose();
187 throw;
188 }
189 }
190 }
191}
Represents the header that must be present for every server request.
Definition: ApiHeaders.cs:22
const string BearerAuthenticationScheme
The JWT authentication header scheme.
Definition: ApiHeaders.cs:41
Public information about a given OAuthProvider.
Uri RedirectUrl
The authentication server URL. Not used by all providers.
Uri UserInformationUrlOverride
User information URL override. Not supported by the Api.Models.OAuthProvider.GitHub provider.
Uri ServerUrl
The client redirect URL. Not used by all providers.
IOAuthValidator for generic OAuth2 endpoints.
GenericOAuthValidator(IAbstractHttpClientFactory httpClientFactory, ILogger< GenericOAuthValidator > logger, OAuthConfiguration oAuthConfiguration)
Initializes a new instance of the GenericOAuthValidator class.
async Task< string > ValidateResponseCode(string code, CancellationToken cancellationToken)
Validate a given OAuth response code . A Task<TResult> resulting in null if authentication failed,...
abstract OAuthProvider Provider
The OAuthProvider this validator is for.
abstract OAuthTokenRequest CreateTokenRequest(string code)
Create the OAuthTokenRequest for a given code .
abstract string DecodeTokenPayload(dynamic responseJson)
Decode the token payload responseJson .
ILogger< GenericOAuthValidator > Logger
The ILogger for the GenericOAuthValidator.
abstract Uri UserInformationUrl
Uri to HttpMethod.Get the user information payload from.
abstract Uri TokenUrl
Uri to HttpMethod.Post to to get the access token.
abstract string DecodeUserInformationPayload(dynamic responseJson)
Decode the user information payload responseJson .
Task< OAuthProviderInfo > GetProviderInfo(CancellationToken cancellationToken)
Gets the OAuthProvider of validator. A Task<TResult> resulting in the client ID of the validator on s...
readonly IAbstractHttpClientFactory httpClientFactory
The IHttpClientFactory for the GenericOAuthValidator.
IHttpClient CreateHttpClient()
Create a new configured IHttpClient.
static JsonSerializerSettings SerializerSettings()
Gets JsonSerializerSettings that should be used.
IHttpClient CreateClient()
Create a IHttpClient.
For sending HTTP requests.
Definition: IHttpClient.cs:13
HttpRequestHeaders DefaultRequestHeaders
The HttpRequestHeaders used on every request.
Definition: IHttpClient.cs:22
Validates OAuth responses for a given Provider.
OAuthProvider
List of OAuth providers supported by TGS.