Skip to content
Merged

Dev #1979

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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace Unity.GrantManager.Applicants
{
public class ApplicantProfileDto
{
public Guid ProfileId { get; set; }
public string Subject { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Unity.GrantManager.Applicants
{
public class ApplicantProfileRequest
{
public Guid ProfileId { get; set; } = Guid.NewGuid();
public string Subject { get; set; } = string.Empty;
public string Issuer { get; set; } = string.Empty;
}

public class TenantedApplicantProfileRequest : ApplicantProfileRequest
{
public Guid TenantId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Unity.GrantManager.Applicants
{
public class ApplicantTenantDto
{
public Guid TenantId { get; set; }
public string TenantName { get; set; } = string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Unity.GrantManager.Applicants
{
public interface IApplicantProfileAppService
{
Task<ApplicantProfileDto> GetApplicantProfileAsync(ApplicantProfileRequest request);
Task<List<ApplicantTenantDto>> GetApplicantTenantsAsync(ApplicantProfileRequest request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity.GrantManager.Applications;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
using Volo.Abp.TenantManagement;

namespace Unity.GrantManager.Applicants
{
[RemoteService(false)]
public class ApplicantProfileAppService(ICurrentTenant currentTenant,
ITenantRepository tenantRepository,
IRepository<ApplicationFormSubmission, Guid> applicationFormSubmissionRepository)
: ApplicationService, IApplicantProfileAppService
{
public async Task<ApplicantProfileDto> GetApplicantProfileAsync(ApplicantProfileRequest request)
{
return await Task.FromResult(new ApplicantProfileDto
{
ProfileId = request.ProfileId,
Subject = request.Subject,
Issuer = request.Issuer,
Email = string.Empty,
DisplayName = string.Empty
});
}

public async Task<List<ApplicantTenantDto>> GetApplicantTenantsAsync(ApplicantProfileRequest request)
{
// Extract the username part from the OIDC sub (part before '@')
var subUsername = request.Subject.Contains('@')
? request.Subject[..request.Subject.IndexOf('@')].ToUpper()
: request.Subject.ToUpper();

var result = new List<ApplicantTenantDto>();

// Get all tenants from the host context
using (currentTenant.Change(null))
{
var tenants = await tenantRepository.GetListAsync();

// Query each tenant's database for matching submissions
foreach (var tenant in tenants)
{
using (currentTenant.Change(tenant.Id))
{
var queryable = await applicationFormSubmissionRepository.GetQueryableAsync();
var hasMatchingSubmission = queryable.Any(s => s.OidcSub == subUsername);

if (hasMatchingSubmission)
{
result.Add(new ApplicantTenantDto
{
TenantId = tenant.Id,
TenantName = tenant.Name
});
}
}
}
}

return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Unity.GrantManager.Applicants;
using Unity.GrantManager.Controllers.Authentication;
using Volo.Abp.AspNetCore.Mvc;

namespace Unity.GrantManager.Controllers
{
[ApiController]
[Route("api/app/applicant-profiles")]
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
public class ApplicantProfileController(IApplicantProfileAppService applicantProfileAppService) : AbpControllerBase
{

[HttpGet]
[Route("profile")]
public async Task<IActionResult> GetApplicantProfileAsync([FromQuery] TenantedApplicantProfileRequest applicantProfileRequest)
{
var profile = await applicantProfileAppService.GetApplicantProfileAsync(applicantProfileRequest);
return Ok(profile);
}

[HttpGet]
[Route("tenants")]
public async Task<IActionResult> GetApplicantProfileTenantsAsync([FromQuery] ApplicantProfileRequest applicantProfileRequest)
{
var tenants = await applicantProfileAppService.GetApplicantTenantsAsync(applicantProfileRequest);
return Ok(tenants);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Unity.GrantManager.ApplicationForms;

namespace Unity.GrantManager.Controllers.Authentication
{
public class ApiKeyAuthorizationFilter(IConfiguration configuration) : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.Request.Headers.TryGetValue(AuthConstants.ApiKeyHeader, out var extractedApiKey))
{
context.Result = new UnauthorizedObjectResult(new ProblemDetails
{
Status = StatusCodes.Status401Unauthorized,
Title = "Unauthorized",
Detail = "API Key missing",
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
});
return;
}

var apiKey = configuration["B2BAuth:ApiKey"];

if (apiKey is null)
{
context.Result = new UnauthorizedObjectResult(new ProblemDetails
{
Status = StatusCodes.Status401Unauthorized,
Title = "Unauthorized",
Detail = "API Key not configured",
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
});
return;
}

if (apiKey != extractedApiKey)
{
context.Result = new UnauthorizedObjectResult(new ProblemDetails
{
Status = StatusCodes.Status401Unauthorized,
Title = "Unauthorized",
Detail = "Invalid API Key",
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
});
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using Volo.Abp.PermissionManagement.HttpApi;
using Volo.Abp.SettingManagement;
using Unity.Notifications;
using Unity.GrantManager.Controllers.Authentication;
using Microsoft.Extensions.DependencyInjection;

namespace Unity.GrantManager;

Expand All @@ -25,7 +27,10 @@ public class GrantManagerHttpApiModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;

ConfigureLocalization();
ConfigureFilters(services);
}

private void ConfigureLocalization()
Expand All @@ -39,4 +44,9 @@ private void ConfigureLocalization()
);
});
}

private static void ConfigureFilters(IServiceCollection services)
{
services.AddScoped<ApiKeyAuthorizationFilter>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="System.Text.Json" Version="9.0.5" />
<PackageReference Include="Volo.Abp.Identity.HttpApi" Version="9.1.3" />
<PackageReference Include="Volo.Abp.PermissionManagement.HttpApi" Version="9.1.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,8 @@
},
"IdentityProfileLogin": {
"AutoCreateUser": true
}
},
"B2BAuth": {
"ApiKey": ""
}
}