Resolve "Module configuration" #48

Merged
leon.hoppe merged 6 commits from feature/moduleConfig into dev 2024-12-23 12:40:41 +01:00
4 changed files with 25 additions and 24 deletions
Showing only changes of commit 849ad649a8 - Show all commits

View File

@@ -9,7 +9,7 @@ using Microsoft.Extensions.Options;
namespace HopFrame.Api.Controller; namespace HopFrame.Api.Controller;
[ApiController, Route("api/v1/openid")] [ApiController, Route("api/v1/openid")]
public class OpenIdController(IOpenIdAccessor accessor, IOptions<OpenIdOptions> options) : ControllerBase { public class OpenIdController(IOpenIdAccessor accessor) : ControllerBase {
public const string DefaultCallback = "api/v1/openid/callback"; public const string DefaultCallback = "api/v1/openid/callback";
[HttpGet("redirect")] [HttpGet("redirect")]
@@ -35,16 +35,7 @@ public class OpenIdController(IOpenIdAccessor accessor, IOptions<OpenIdOptions>
return Forbid("Authorization code is not valid"); return Forbid("Authorization code is not valid");
} }
Response.Cookies.Append(ITokenContext.AccessTokenType, token.AccessToken, new CookieOptions { accessor.SetAuthenticationCookies(token);
MaxAge = TimeSpan.FromSeconds(token.ExpiresIn),
HttpOnly = false,
Secure = true
});
Response.Cookies.Append(ITokenContext.RefreshTokenType, token.RefreshToken, new CookieOptions {
MaxAge = options.Value.RefreshToken.ConstructTimeSpan,
HttpOnly = false,
Secure = true
});
if (string.IsNullOrEmpty(state)) { if (string.IsNullOrEmpty(state)) {
return Ok(new SingleValueResult<string>(token.AccessToken)); return Ok(new SingleValueResult<string>(token.AccessToken));
@@ -65,11 +56,7 @@ public class OpenIdController(IOpenIdAccessor accessor, IOptions<OpenIdOptions>
if (token is null) if (token is null)
return NotFound("Refresh token not valid"); return NotFound("Refresh token not valid");
Response.Cookies.Append(ITokenContext.AccessTokenType, token.AccessToken, new CookieOptions { accessor.SetAuthenticationCookies(token);
MaxAge = TimeSpan.FromSeconds(token.ExpiresIn),
HttpOnly = false,
Secure = true
});
return Ok(new SingleValueResult<string>(token.AccessToken)); return Ok(new SingleValueResult<string>(token.AccessToken));
} }

View File

@@ -10,4 +10,5 @@ public interface IOpenIdAccessor {
Task<string> ConstructAuthUri(string state = null); Task<string> ConstructAuthUri(string state = null);
Task<OpenIdIntrospection> InspectToken(string token); Task<OpenIdIntrospection> InspectToken(string token);
Task<OpenIdToken> RefreshAccessToken(string refreshToken); Task<OpenIdToken> RefreshAccessToken(string refreshToken);
void SetAuthenticationCookies(OpenIdToken token);
} }

View File

@@ -1,6 +1,7 @@
using System.Text.Json; using System.Text.Json;
using HopFrame.Security.Authentication.OpenID.Models; using HopFrame.Security.Authentication.OpenID.Models;
using HopFrame.Security.Authentication.OpenID.Options; using HopFrame.Security.Authentication.OpenID.Options;
using HopFrame.Security.Claims;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@@ -18,7 +19,7 @@ internal class OpenIdAccessor(IHttpClientFactory clientFactory, IOptions<OpenIdO
} }
var client = clientFactory.CreateClient(); var client = clientFactory.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, Path.Combine(options.Value.Issuer, ".well-known/openid-configuration")); var request = new HttpRequestMessage(HttpMethod.Get, Path.Combine(options.Value.Issuer, ".well-known/openid-configuration").Replace("\\", "/"));
var response = await client.SendAsync(request); var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
@@ -38,7 +39,7 @@ internal class OpenIdAccessor(IHttpClientFactory clientFactory, IOptions<OpenIdO
} }
var protocol = accessor.HttpContext!.Request.IsHttps ? "https" : "http"; var protocol = accessor.HttpContext!.Request.IsHttps ? "https" : "http";
var callback = options.Value.Callback ?? Path.Combine($"{protocol}://{accessor.HttpContext!.Request.Host.Value}", IOpenIdAccessor.DefaultCallback); var callback = options.Value.Callback ?? Path.Combine($"{protocol}://{accessor.HttpContext!.Request.Host.Value}", IOpenIdAccessor.DefaultCallback).Replace("\\", "/");
var configuration = await LoadConfiguration(); var configuration = await LoadConfiguration();
@@ -67,7 +68,7 @@ internal class OpenIdAccessor(IHttpClientFactory clientFactory, IOptions<OpenIdO
public async Task<string> ConstructAuthUri(string state = null) { public async Task<string> ConstructAuthUri(string state = null) {
var protocol = accessor.HttpContext!.Request.IsHttps ? "https" : "http"; var protocol = accessor.HttpContext!.Request.IsHttps ? "https" : "http";
var callback = options.Value.Callback ?? Path.Combine($"{protocol}://{accessor.HttpContext!.Request.Host.Value}", IOpenIdAccessor.DefaultCallback); var callback = options.Value.Callback ?? Path.Combine($"{protocol}://{accessor.HttpContext!.Request.Host.Value}", IOpenIdAccessor.DefaultCallback).Replace("\\", "/");
var configuration = await LoadConfiguration(); var configuration = await LoadConfiguration();
return $"{configuration.AuthorizationEndpoint}?response_type=code&client_id={options.Value.ClientId}&redirect_uri={callback}&scope=openid%20profile%20email%20offline_access&state={state}"; return $"{configuration.AuthorizationEndpoint}?response_type=code&client_id={options.Value.ClientId}&redirect_uri={callback}&scope=openid%20profile%20email%20offline_access&state={state}";
@@ -120,4 +121,20 @@ internal class OpenIdAccessor(IHttpClientFactory clientFactory, IOptions<OpenIdO
return await JsonSerializer.DeserializeAsync<OpenIdToken>(await response.Content.ReadAsStreamAsync()); return await JsonSerializer.DeserializeAsync<OpenIdToken>(await response.Content.ReadAsStreamAsync());
} }
public void SetAuthenticationCookies(OpenIdToken token) {
if (token.AccessToken is not null)
accessor.HttpContext!.Response.Cookies.Append(ITokenContext.AccessTokenType, token.AccessToken, new CookieOptions {
MaxAge = TimeSpan.FromSeconds(token.ExpiresIn),
HttpOnly = false,
Secure = true
});
if (token.RefreshToken is not null)
accessor.HttpContext!.Response.Cookies.Append(ITokenContext.RefreshTokenType, token.RefreshToken, new CookieOptions {
MaxAge = options.Value.RefreshToken.ConstructTimeSpan,
HttpOnly = false,
Secure = true
});
}
} }

View File

@@ -108,11 +108,7 @@ internal class AuthService(
}); });
} }
httpAccessor.HttpContext?.Response.Cookies.Append(ITokenContext.AccessTokenType, openIdToken.AccessToken, new CookieOptions { accessor.SetAuthenticationCookies(openIdToken);
MaxAge = TimeSpan.FromSeconds(openIdToken.ExpiresIn),
HttpOnly = false,
Secure = true
});
return new() { return new() {
Owner = user, Owner = user,
CreatedAt = DateTime.Now, CreatedAt = DateTime.Now,