identity: add proxy controller
This commit is contained in:
parent
727f2f6ba2
commit
b95fb76cd4
9 changed files with 446 additions and 10 deletions
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
|
|||
using Foxchat.Identity.Database.Models;
|
||||
using Foxchat.Core;
|
||||
using System.Diagnostics;
|
||||
using Foxchat.Identity.Utils;
|
||||
using NodaTime;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -24,10 +25,11 @@ public class PasswordAuthController(ILogger logger, IdentityContext db, IClock c
|
|||
var appToken =
|
||||
HttpContext.GetToken() ??
|
||||
throw new UnreachableException(); // GetApplicationOrThrow already gets the token and throws if it's null
|
||||
var appScopes = appToken.ExpandScopes();
|
||||
|
||||
if (req.Scopes.Except(appToken.Scopes).Any())
|
||||
if (req.Scopes.Except(appScopes).Any())
|
||||
throw new ApiError.Forbidden("Cannot request token scopes that are not allowed for this token",
|
||||
req.Scopes.Except(appToken.Scopes));
|
||||
req.Scopes.Except(appScopes));
|
||||
|
||||
var acct = new Account
|
||||
{
|
||||
|
@ -52,10 +54,11 @@ public class PasswordAuthController(ILogger logger, IdentityContext db, IClock c
|
|||
{
|
||||
var app = HttpContext.GetApplicationOrThrow();
|
||||
var appToken = HttpContext.GetToken() ?? throw new UnreachableException();
|
||||
var appScopes = appToken.ExpandScopes();
|
||||
|
||||
if (req.Scopes.Except(appToken.Scopes).Any())
|
||||
if (req.Scopes.Except(appScopes).Any())
|
||||
throw new ApiError.Forbidden("Cannot request token scopes that are not allowed for this token",
|
||||
req.Scopes.Except(appToken.Scopes));
|
||||
req.Scopes.Except(appScopes));
|
||||
|
||||
var acct = await db.Accounts.FirstOrDefaultAsync(a => a.Email == req.Email)
|
||||
?? throw new ApiError.NotFound("No user with that email found, or password is incorrect");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Foxchat.Core;
|
||||
using Foxchat.Identity.Database;
|
||||
using Foxchat.Identity.Database.Models;
|
||||
using Foxchat.Identity.Utils;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NodaTime;
|
||||
|
||||
|
@ -14,11 +15,12 @@ public class TokenController(ILogger logger, IdentityContext db, IClock clock) :
|
|||
public async Task<IActionResult> PostToken([FromBody] PostTokenRequest req)
|
||||
{
|
||||
var app = await db.GetApplicationAsync(req.ClientId, req.ClientSecret);
|
||||
var appScopes = app.ExpandScopes();
|
||||
|
||||
var scopes = req.Scope.Split(' ');
|
||||
if (scopes.Except(app.Scopes).Any())
|
||||
if (scopes.Except(appScopes).Any())
|
||||
{
|
||||
throw new ApiError.BadRequest("Invalid or unauthorized scopes");
|
||||
throw new ApiError.Forbidden("Invalid or unauthorized scopes", scopes.Except(appScopes));
|
||||
}
|
||||
|
||||
switch (req.GrantType)
|
||||
|
|
21
Foxchat.Identity/Controllers/Proxy/GuildsProxyController.cs
Normal file
21
Foxchat.Identity/Controllers/Proxy/GuildsProxyController.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using Foxchat.Core.Federation;
|
||||
using Foxchat.Core.Models;
|
||||
using Foxchat.Core.Models.Http;
|
||||
using Foxchat.Identity.Middleware;
|
||||
using Foxchat.Identity.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Foxchat.Identity.Controllers.Proxy;
|
||||
|
||||
[Route("/_fox/proxy/guilds")]
|
||||
public class GuildsProxyController(
|
||||
ILogger logger,
|
||||
ChatInstanceResolverService chatInstanceResolverService,
|
||||
RequestSigningService requestSigningService)
|
||||
: ProxyControllerBase(logger, chatInstanceResolverService, requestSigningService)
|
||||
{
|
||||
[Authorize("chat_client")]
|
||||
[HttpPost]
|
||||
public Task<IActionResult> CreateGuild([FromBody] GuildsApi.CreateGuildRequest req) =>
|
||||
Proxy<Guilds.Guild>(HttpMethod.Post, req);
|
||||
}
|
38
Foxchat.Identity/Controllers/Proxy/ProxyControllerBase.cs
Normal file
38
Foxchat.Identity/Controllers/Proxy/ProxyControllerBase.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using Foxchat.Core;
|
||||
using Foxchat.Core.Federation;
|
||||
using Foxchat.Identity.Middleware;
|
||||
using Foxchat.Identity.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Foxchat.Identity.Controllers.Proxy;
|
||||
|
||||
[ApiController]
|
||||
[ClientAuthenticate]
|
||||
public class ProxyControllerBase(
|
||||
ILogger logger,
|
||||
ChatInstanceResolverService chatInstanceResolverService,
|
||||
RequestSigningService requestSigningService) : ControllerBase
|
||||
{
|
||||
internal async Task<IActionResult> Proxy<TResponse>(HttpMethod method, object? body = null) where TResponse : class
|
||||
{
|
||||
var acct = HttpContext.GetAccountOrThrow();
|
||||
|
||||
var path = HttpContext.Request.Path.ToString();
|
||||
if (!path.StartsWith("/_fox/proxy"))
|
||||
throw new FoxchatError("Proxy<T> used for endpoint that does not start with /_fox/proxy");
|
||||
path = $"/_fox/chat/{path[12..]}";
|
||||
|
||||
if (!HttpContext.Request.Headers.TryGetValue(RequestSigningService.SERVER_HEADER, out var serverHeader))
|
||||
throw new ApiError.BadRequest($"Invalid or missing {RequestSigningService.SERVER_HEADER} header.");
|
||||
var server = serverHeader.ToString();
|
||||
|
||||
logger.Debug("Proxying {Method} request to {Domain}{Path}", method, server, path);
|
||||
|
||||
// Identity instances always initiate federation, so we have to make sure the instance knows about us.
|
||||
// This also serves as a way to make sure the instance being requested actually exists.
|
||||
await chatInstanceResolverService.ResolveChatInstanceAsync(serverHeader.ToString());
|
||||
|
||||
var resp = await requestSigningService.RequestAsync<TResponse>(method, server, path, acct.Id.ToString(), body);
|
||||
return Ok(resp);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue