Skip to content

Commit 3e04d38

Browse files
Merge pull request #1979 from bcgov/dev
Dev
2 parents 2bfdaf4 + 2b82a6e commit 3e04d38

10 files changed

Lines changed: 217 additions & 3 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
3+
namespace Unity.GrantManager.Applicants
4+
{
5+
public class ApplicantProfileDto
6+
{
7+
public Guid ProfileId { get; set; }
8+
public string Subject { get; set; } = string.Empty;
9+
public string Issuer { get; set; } = string.Empty;
10+
public string Email { get; set; } = string.Empty;
11+
public string DisplayName { get; set; } = string.Empty;
12+
}
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace Unity.GrantManager.Applicants
4+
{
5+
public class ApplicantProfileRequest
6+
{
7+
public Guid ProfileId { get; set; } = Guid.NewGuid();
8+
public string Subject { get; set; } = string.Empty;
9+
public string Issuer { get; set; } = string.Empty;
10+
}
11+
12+
public class TenantedApplicantProfileRequest : ApplicantProfileRequest
13+
{
14+
public Guid TenantId { get; set; }
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace Unity.GrantManager.Applicants
4+
{
5+
public class ApplicantTenantDto
6+
{
7+
public Guid TenantId { get; set; }
8+
public string TenantName { get; set; } = string.Empty;
9+
}
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
4+
namespace Unity.GrantManager.Applicants
5+
{
6+
public interface IApplicantProfileAppService
7+
{
8+
Task<ApplicantProfileDto> GetApplicantProfileAsync(ApplicantProfileRequest request);
9+
Task<List<ApplicantTenantDto>> GetApplicantTenantsAsync(ApplicantProfileRequest request);
10+
}
11+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Unity.GrantManager.Applications;
6+
using Volo.Abp;
7+
using Volo.Abp.Application.Services;
8+
using Volo.Abp.Domain.Repositories;
9+
using Volo.Abp.MultiTenancy;
10+
using Volo.Abp.TenantManagement;
11+
12+
namespace Unity.GrantManager.Applicants
13+
{
14+
[RemoteService(false)]
15+
public class ApplicantProfileAppService(ICurrentTenant currentTenant,
16+
ITenantRepository tenantRepository,
17+
IRepository<ApplicationFormSubmission, Guid> applicationFormSubmissionRepository)
18+
: ApplicationService, IApplicantProfileAppService
19+
{
20+
public async Task<ApplicantProfileDto> GetApplicantProfileAsync(ApplicantProfileRequest request)
21+
{
22+
return await Task.FromResult(new ApplicantProfileDto
23+
{
24+
ProfileId = request.ProfileId,
25+
Subject = request.Subject,
26+
Issuer = request.Issuer,
27+
Email = string.Empty,
28+
DisplayName = string.Empty
29+
});
30+
}
31+
32+
public async Task<List<ApplicantTenantDto>> GetApplicantTenantsAsync(ApplicantProfileRequest request)
33+
{
34+
// Extract the username part from the OIDC sub (part before '@')
35+
var subUsername = request.Subject.Contains('@')
36+
? request.Subject[..request.Subject.IndexOf('@')].ToUpper()
37+
: request.Subject.ToUpper();
38+
39+
var result = new List<ApplicantTenantDto>();
40+
41+
// Get all tenants from the host context
42+
using (currentTenant.Change(null))
43+
{
44+
var tenants = await tenantRepository.GetListAsync();
45+
46+
// Query each tenant's database for matching submissions
47+
foreach (var tenant in tenants)
48+
{
49+
using (currentTenant.Change(tenant.Id))
50+
{
51+
var queryable = await applicationFormSubmissionRepository.GetQueryableAsync();
52+
var hasMatchingSubmission = queryable.Any(s => s.OidcSub == subUsername);
53+
54+
if (hasMatchingSubmission)
55+
{
56+
result.Add(new ApplicantTenantDto
57+
{
58+
TenantId = tenant.Id,
59+
TenantName = tenant.Name
60+
});
61+
}
62+
}
63+
}
64+
}
65+
66+
return result;
67+
}
68+
}
69+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using System.Threading.Tasks;
3+
using Unity.GrantManager.Applicants;
4+
using Unity.GrantManager.Controllers.Authentication;
5+
using Volo.Abp.AspNetCore.Mvc;
6+
7+
namespace Unity.GrantManager.Controllers
8+
{
9+
[ApiController]
10+
[Route("api/app/applicant-profiles")]
11+
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
12+
public class ApplicantProfileController(IApplicantProfileAppService applicantProfileAppService) : AbpControllerBase
13+
{
14+
15+
[HttpGet]
16+
[Route("profile")]
17+
public async Task<IActionResult> GetApplicantProfileAsync([FromQuery] TenantedApplicantProfileRequest applicantProfileRequest)
18+
{
19+
var profile = await applicantProfileAppService.GetApplicantProfileAsync(applicantProfileRequest);
20+
return Ok(profile);
21+
}
22+
23+
[HttpGet]
24+
[Route("tenants")]
25+
public async Task<IActionResult> GetApplicantProfileTenantsAsync([FromQuery] ApplicantProfileRequest applicantProfileRequest)
26+
{
27+
var tenants = await applicantProfileAppService.GetApplicantTenantsAsync(applicantProfileRequest);
28+
return Ok(tenants);
29+
}
30+
}
31+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.AspNetCore.Mvc.Filters;
4+
using Microsoft.Extensions.Configuration;
5+
using Unity.GrantManager.ApplicationForms;
6+
7+
namespace Unity.GrantManager.Controllers.Authentication
8+
{
9+
public class ApiKeyAuthorizationFilter(IConfiguration configuration) : IAuthorizationFilter
10+
{
11+
public void OnAuthorization(AuthorizationFilterContext context)
12+
{
13+
if (!context.HttpContext.Request.Headers.TryGetValue(AuthConstants.ApiKeyHeader, out var extractedApiKey))
14+
{
15+
context.Result = new UnauthorizedObjectResult(new ProblemDetails
16+
{
17+
Status = StatusCodes.Status401Unauthorized,
18+
Title = "Unauthorized",
19+
Detail = "API Key missing",
20+
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
21+
});
22+
return;
23+
}
24+
25+
var apiKey = configuration["B2BAuth:ApiKey"];
26+
27+
if (apiKey is null)
28+
{
29+
context.Result = new UnauthorizedObjectResult(new ProblemDetails
30+
{
31+
Status = StatusCodes.Status401Unauthorized,
32+
Title = "Unauthorized",
33+
Detail = "API Key not configured",
34+
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
35+
});
36+
return;
37+
}
38+
39+
if (apiKey != extractedApiKey)
40+
{
41+
context.Result = new UnauthorizedObjectResult(new ProblemDetails
42+
{
43+
Status = StatusCodes.Status401Unauthorized,
44+
Title = "Unauthorized",
45+
Detail = "Invalid API Key",
46+
Type = "https://tools.ietf.org/html/rfc7235#section-3.1"
47+
});
48+
}
49+
}
50+
}
51+
}

applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/GrantManagerHttpApiModule.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using Volo.Abp.PermissionManagement.HttpApi;
99
using Volo.Abp.SettingManagement;
1010
using Unity.Notifications;
11+
using Unity.GrantManager.Controllers.Authentication;
12+
using Microsoft.Extensions.DependencyInjection;
1113

1214
namespace Unity.GrantManager;
1315

@@ -25,7 +27,10 @@ public class GrantManagerHttpApiModule : AbpModule
2527
{
2628
public override void ConfigureServices(ServiceConfigurationContext context)
2729
{
30+
var services = context.Services;
31+
2832
ConfigureLocalization();
33+
ConfigureFilters(services);
2934
}
3035

3136
private void ConfigureLocalization()
@@ -39,4 +44,9 @@ private void ConfigureLocalization()
3944
);
4045
});
4146
}
47+
48+
private static void ConfigureFilters(IServiceCollection services)
49+
{
50+
services.AddScoped<ApiKeyAuthorizationFilter>();
51+
}
4252
}

applications/Unity.GrantManager/src/Unity.GrantManager.HttpApi/Unity.GrantManager.HttpApi.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
<ItemGroup>
1818
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.5" />
19-
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.5" />
19+
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.5" />
2020
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
21-
<PackageReference Include="RestSharp" Version="112.1.0" />
21+
<PackageReference Include="RestSharp" Version="112.1.0" />
2222
<PackageReference Include="System.Text.Json" Version="9.0.5" />
2323
<PackageReference Include="Volo.Abp.Identity.HttpApi" Version="9.1.3" />
2424
<PackageReference Include="Volo.Abp.PermissionManagement.HttpApi" Version="9.1.3" />

applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,8 @@
9494
},
9595
"IdentityProfileLogin": {
9696
"AutoCreateUser": true
97-
}
97+
},
98+
"B2BAuth": {
99+
"ApiKey": ""
100+
}
98101
}

0 commit comments

Comments
 (0)