Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CSLabs.Api/Jobs/ApiTokenJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Threading.Tasks;
using CSLabs.Api.Models;
using CSLabs.Api.Services;
using FluentScheduler;
using Microsoft.Extensions.DependencyInjection;

namespace CSLabs.Api.Jobs
{
public class ApiTokenJob : AsyncJob
{
private readonly IServiceProvider _serviceProvider;

public ApiTokenJob(IServiceProvider provider)
{
_serviceProvider = provider;
}

protected override async Task ExecuteAsync()
{
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetService<DefaultContext>();
var service = scope.ServiceProvider.GetService<ProxmoxApiTokenService>();

await service.ManageApiToken(context);
}
}
}
2 changes: 1 addition & 1 deletion CSLabs.Api/Jobs/JobRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public JobRegistry(IServiceProvider provider)

// Schedule new jobs here
Schedule(() => new ExampleJob(provider)).ToRunEvery(1).Minutes();

Schedule(() => new ApiTokenJob(provider)).ToRunOnceAt(DateTime.Now).AndEvery(30).Days().At(0, 0);
}
}
}
45 changes: 45 additions & 0 deletions CSLabs.Api/Proxmox/ProxmoxApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Corsinvest.ProxmoxVE.Api;
using Corsinvest.ProxmoxVE.Api.Extension.Info;
using CSLabs.Api.Models.HypervisorModels;
using CSLabs.Api.Models.UserModels;
using CSLabs.Api.Proxmox.Responses;
using Newtonsoft.Json;

Expand All @@ -17,6 +18,7 @@ public class ProxmoxApi
private PveClient client;
private DateTime _loggedInAt = DateTime.MinValue;
private string _password;

public HypervisorNode HypervisorNode { get;}
public ProxmoxApi(HypervisorNode hypervisorNode, string password)
{
Expand All @@ -40,6 +42,49 @@ private async Task Login()
_loggedInAt = DateTime.Now;
}

public async Task ManageApiToken()
{
await LoginIfNotLoggedIn();
var userid = $"{HypervisorNode.Hypervisor.UserName}@pam";
if (string.IsNullOrEmpty(client.ApiToken))
await GenerateApiToken(userid);
else
await RotateApiToken(userid);
}

private async Task RotateApiToken(string userid)
{
await LoginIfNotLoggedIn();
await PerformRequest(() => client.Access.Users[userid].Token["API_TOKEN"].RemoveToken());
await GenerateApiToken(userid);
}

private async Task GenerateApiToken(string userid)
{
await LoginIfNotLoggedIn();
var apiTokenResponse = await GetApiToken(userid);
client.ApiToken = $"{userid}!API_TOKEN={apiTokenResponse.Value}";
}

private async Task<ApiTokenResponse> GetApiToken(string userid)
{
await LoginIfNotLoggedIn();
var expireDate = (int) DateTimeOffset.UtcNow.AddDays(30).ToUnixTimeSeconds();
var apiKey = await PerformRequest(() =>
client.Access.Users[userid].Token["API_TOKEN"].GenerateToken(expire: expireDate, privsep: true));

return new ApiTokenResponse()
{
FullTokenId = ((IDictionary<string, object>) apiKey.Response.data)["full-tokenid"].ToString(),
Info = new TokenInfo()
{
Expire = int.Parse(apiKey.Response.data.info.expire),
PrivSep = apiKey.Response.data.info.privsep == "1"
},
Value = apiKey.Response.data.value
};
}

public async Task<TicketResponse> GetTicket(int vmId)

@zkhussain zkhussain Jan 23, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasekiw Using API tokens gets rid of the need to log in to the proxmox API with username and password. The Login method we use logs in and generates a ticket, which is used to authenticate noVNC in cslabs-webapp/src/api/rfb.ts. Since API tokens will remove the need for log in, a ticket will not be generated to authenticate to noVNC, and I am receiving a 401 unauthorized if I do so. Reference to the proxmox API here. I may have missed something, I am not sure what we can do or maybe there is another way?

@jasekiw jasekiw Apr 4, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zkhussain Is there a time you are available to go through this via zoom? I would like you to demonstrate the issue for me if you can.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, evening times work best. Tomorrow after the meeting?

{
await LoginIfNotLoggedIn();
Expand Down
16 changes: 16 additions & 0 deletions CSLabs.Api/Proxmox/Responses/ApiTokenResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace CSLabs.Api.Proxmox.Responses
{
public class ApiTokenResponse
{
public string Value { get; set; }
public TokenInfo Info { get; set; }
public string FullTokenId { get; set; }
}

public class TokenInfo
{
public string Comment { get; set; }
public int Expire { get; set; }
public bool PrivSep { get; set; }
}
}
27 changes: 27 additions & 0 deletions CSLabs.Api/Services/ProxmoxApiTokenService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using CSLabs.Api.Models;
using CSLabs.Api.Proxmox;
using Microsoft.EntityFrameworkCore;

namespace CSLabs.Api.Services
{
public class ProxmoxApiTokenService
{
public ProxmoxManager ProxmoxManager { get;}

public ProxmoxApiTokenService(ProxmoxManager manager)
{
ProxmoxManager = manager;
}

public async Task ManageApiToken(DefaultContext context)
{
var hypervisor = await context.Hypervisors.FirstOrDefaultAsync();
var primaryHypervisorNode = await ProxmoxManager.GetPrimaryHypervisorNode(hypervisor);
var api = ProxmoxManager.GetProxmoxApi(primaryHypervisorNode);
await api.ManageApiToken();
}
}
}
1 change: 1 addition & 0 deletions CSLabs.Api/Services/ServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static void ProvideAppServices(this IServiceCollection services)
services.AddScoped<IAuthenticationService, AuthenticationService>();
services.ProvideProxmoxApi();
services.AddScoped<BaseControllerDependencies>();
services.AddScoped<ProxmoxApiTokenService>();
services.AddTransient<UserLabInstantiationService>();
services.AddTransient<ProxmoxVmTemplateService>();
services.AddSingleton<UrlBasedUploadManager>();
Expand Down