Skip to content

Commit

Permalink
Merge pull request #106 from bcgov/yj
Browse files Browse the repository at this point in the history
chore: bceid soap
  • Loading branch information
ychung-mot authored Apr 9, 2024
2 parents 541698e + 4998928 commit dd6c908
Show file tree
Hide file tree
Showing 21 changed files with 4,409 additions and 17 deletions.
3 changes: 2 additions & 1 deletion helm/main/values-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ global:
'CHES_TOKEN_URL': 'https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token'
'CHES_URL': 'https://ches-dev.api.gov.bc.ca'
'RENTAL_LISTING_REPORT_MAX_SIZE': '4'

'BCEID_URL': 'https://gws1.development.bceid.ca/webservices/client/v10/bceidservice.asmx'
'BCEID_CACHE_LIFESPAN': '600'
nameOverride: strdss-dev
fullnameOverride: strdss-dev

Expand Down
2 changes: 2 additions & 0 deletions helm/main/values-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ global:
'CHES_TOKEN_URL': 'https://loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token'
'CHES_URL': 'https://ches.api.gov.bc.ca'
'RENTAL_LISTING_REPORT_MAX_SIZE': '4'
'BCEID_URL': 'https://gws1.bceid.ca/webservices/client/v10/bceidservice.asmx'
'BCEID_CACHE_LIFESPAN': '600'

nameOverride: strdss-prod
fullnameOverride: strdss-prod
Expand Down
2 changes: 2 additions & 0 deletions helm/main/values-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ global:
'CHES_TOKEN_URL': 'https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token'
'CHES_URL': 'https://ches-dev.api.gov.bc.ca'
'RENTAL_LISTING_REPORT_MAX_SIZE': '4'
'BCEID_URL': 'https://gws1.development.bceid.ca/webservices/client/v10/bceidservice.asmx'
'BCEID_CACHE_LIFESPAN': '600'

nameOverride: strdss-test
fullnameOverride: strdss-test
Expand Down
2 changes: 2 additions & 0 deletions helm/main/values-uat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ global:
'CHES_TOKEN_URL': 'https://test.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token'
'CHES_URL': 'https://ches-test.api.gov.bc.ca'
'RENTAL_LISTING_REPORT_MAX_SIZE': '4'
'BCEID_URL': 'https://gws1.test.bceid.ca/webservices/client/v10/bceidservice.asmx'
'BCEID_CACHE_LIFESPAN': '600'

nameOverride: strdss-uat
fullnameOverride: strdss-uat
Expand Down
2 changes: 1 addition & 1 deletion server/StrDss.Api/Controllers/BaseApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class BaseApiController : ControllerBase
protected ICurrentUser _currentUser;
protected IMapper _mapper;
protected IConfiguration _config;
private ILogger<StrDssLogger> _logger;
protected ILogger<StrDssLogger> _logger;

public BaseApiController(ICurrentUser currentUser, IMapper mapper, IConfiguration config, ILogger<StrDssLogger> logger)
{
Expand Down
3 changes: 0 additions & 3 deletions server/StrDss.Api/Controllers/DelistingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ namespace StrDss.Api.Controllers
public class DelistingController : BaseApiController
{
private IChesTokenApi _chesTokenApi;

private ILogger<StrDssLogger> _logger { get; }
private IDelistingService _delistingService { get; }

private IEmailMessageService _emailService;

public DelistingController(ICurrentUser currentUser, IMapper mapper, IConfiguration config, IChesTokenApi chesTokenApi, ILogger<StrDssLogger> logger,
Expand Down
2 changes: 2 additions & 0 deletions server/StrDss.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using StrDss.Api.Middlewares;
using StrDss.Api;
using StrDss.Service.Hangfire;
using StrDss.Service.Bceid;

var builder = WebApplication.CreateBuilder(args);

Expand Down Expand Up @@ -85,6 +86,7 @@

builder.Services.AddScoped<IApi, Api>();
builder.Services.AddHttpClients(builder.Configuration);
builder.Services.AddBceidSoapClient(builder.Configuration);

var mappingConfig = new MapperConfiguration(cfg =>
{
Expand Down
10 changes: 10 additions & 0 deletions server/StrDss.Common/CommonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,15 @@ public static bool IsNumericType(this Type type)

return false;
}

public static bool IsIdirUser(this string str)
{
return str.ToUpperInvariant() == BceidUserTypes.Internal;
}

public static bool IsBusinessUser(this string str)
{
return str.ToUpperInvariant() == BceidUserTypes.Business;
}
}
}
2 changes: 1 addition & 1 deletion server/StrDss.Data/Repositories/RepositoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class RepositoryBase<TEntity> : IRepositoryBase<TEntity>
protected DbSet<TEntity> _dbSet { get; private set; }

protected ICurrentUser _currentUser;
private ILogger<StrDssLogger> _logger;
protected ILogger<StrDssLogger> _logger;

protected DssDbContext _dbContext { get; private set; }

Expand Down
8 changes: 8 additions & 0 deletions server/StrDss.Service/Bceid/BCeIDServiceSoapClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BceidService
{
public partial class BCeIDServiceSoapClient
{
public string Osid { get; set; } = null!;
public double CacheLifespan { get; set; }
}
}
17 changes: 17 additions & 0 deletions server/StrDss.Service/Bceid/BceidAccount.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace StrDss.Service.Bceid
{
public class BceidAccount
{
public string Username { get; set; } = null!;
public Guid UserGuid { get; set; }
public Guid? BusinessGuid { get; set; }
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string BusinessLegalName { get; set; } = null!;
public decimal BusinessNumber { get; set; }
public string DoingBusinessAs { get; set; } = null!;
public string Email { get; set; } = null!;
public string UserType { get; set; } = null!;
public string DisplayName { get; set; } = null!;
}
}
132 changes: 132 additions & 0 deletions server/StrDss.Service/Bceid/BceidApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System.Diagnostics;
using System.Timers;
using BceidService;
using StrDss.Common;

namespace StrDss.Service.Bceid
{
public interface IBceidApi
{
Task<(string error, BceidAccount? account)> GetBceidAccountCachedAsync(Guid? userGuid, string username, string userType, Guid requestorGuid, string requestorType);
}

public class BceidApi : IBceidApi
{
private readonly BCeIDServiceSoapClient _client;
private readonly Dictionary<string, BceidAccount> _accountCache; //no need for ConcurrentDictionary
private readonly System.Timers.Timer _timer;
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

public BceidApi(BCeIDServiceSoapClient client)
{
_client = client;
_accountCache = new Dictionary<string, BceidAccount>();
_timer = new System.Timers.Timer();
_timer.Elapsed += new ElapsedEventHandler(RefreshCache!);
_timer.Interval = TimeSpan.FromMinutes(_client.CacheLifespan).TotalMilliseconds;
_timer.Enabled = true;
}

private void RefreshCache(object source, ElapsedEventArgs e)
{
Debug.WriteLine($"BCeID Cache clean up: {_accountCache.Keys.Count} entries.");
_accountCache.Clear();
}

public async Task<(string error, BceidAccount? account)> GetBceidAccountCachedAsync(Guid? userGuid, string username, string userType, Guid requestorGuid, string requestorType)
{
//to minimize the BCeID web service calls - may have a performance issue when multiple fresh users log in at the same time.
await _semaphore.WaitAsync();

try
{
var key = username + "||" + userType;
if (_accountCache.ContainsKey(key))
{
Debug.WriteLine($"BCeID cache hit: {key}");
return ("", _accountCache[key]);
}

var (error, account) = await GetBceidAccountAsync(userGuid, username, userType, requestorGuid.ToString("N"), requestorType);

if (account != null)
{
Debug.WriteLine($"BCeID new key: {key}");
_accountCache[key] = account;
}

if (account != null && string.IsNullOrEmpty(account.Username)) account.Username = username;

return (error, account);
}
finally
{
_semaphore.Release();
}
}

private async Task<(string error, BceidAccount? account)> GetBceidAccountAsync(Guid? userGuid, string username, string userType, string requestorGuid, string requestorType)
{
var targetTypeCode = userType.IsIdirUser() ? BCeIDAccountTypeCode.Internal : BCeIDAccountTypeCode.Business;
var requesterTypeCode = requestorType.IsIdirUser() ? BCeIDAccountTypeCode.Internal : BCeIDAccountTypeCode.Business;

var request = new AccountDetailRequest();
request.requesterAccountTypeCode = requesterTypeCode;
request.requesterUserGuid = requestorGuid;
request.accountTypeCode = targetTypeCode;

//ISA - for IDIR, only IDIR search is allowed
if (userType.IsIdirUser())
{
request.userId = username;
}
else if (userGuid != null)
{
request.userGuid = userGuid?.ToString("N");
}
else
{
request.userId = username;
}

request.onlineServiceId = _client.Osid;

var response = await _client.getAccountDetailAsync(request);

if (response.code != ResponseCode.Success)
{
return (response.message, null);
}
else if (response.failureCode == FailureCode.NoResults)
{
return ("", null);
}

var account = new BceidAccount();

account.Username = response.account.userId.value;
account.UserGuid = userGuid ?? new Guid(response.account.guid.value);
account.UserType = userType;

if (account.UserType.IsBusinessUser())
{
account.BusinessGuid = response.account.business.guid.value == "" ? Guid.Empty : new Guid(response.account.business.guid.value);
account.BusinessLegalName = response.account.business.legalName.value;

var doingBusinessAs = response.account.business.doingBusinessAs.value;
account.DoingBusinessAs = doingBusinessAs.IsEmpty() ? account.BusinessLegalName : doingBusinessAs;

var businessNumber = response.account.business.businessNumber.value;
account.BusinessNumber = businessNumber.IsEmpty() ? 0 : Convert.ToDecimal(businessNumber);
}

account.DisplayName = response.account.displayName.value;
account.FirstName = response.account.individualIdentity.name.firstname.value;
account.LastName = response.account.individualIdentity.name.surname.value;
account.Email = response.account.contact.email.value;

return ("", account);
}

}
}
39 changes: 39 additions & 0 deletions server/StrDss.Service/Bceid/BceidServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using static BceidService.BCeIDServiceSoapClient;
using System.ServiceModel;
using BceidService;

namespace StrDss.Service.Bceid
{
public static class BceidServiceCollectionExtensions
{
public static void AddBceidSoapClient(this IServiceCollection services, IConfiguration config)
{
services.AddSingleton<BCeIDServiceSoapClient>(provider =>
{
var username = config.GetValue<string>("SA_USER");
var password = config.GetValue<string>("SA_PASS");
var url = config.GetValue<string>("BCEID_URL");
var osid = config.GetValue<string>("BCEID_OSID");
var cacheLifeSpan = config.GetValue<int>("BCEID_CACHE_LIFESPAN");

var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;

var client = new BCeIDServiceSoapClient(EndpointConfiguration.BCeIDServiceSoap12);
client.ClientCredentials.UserName.UserName = username;
client.ClientCredentials.UserName.Password = password;
client.Endpoint.Binding = binding;
client.Endpoint.Address = new EndpointAddress(url);
client.Osid = osid!;
client.CacheLifespan = cacheLifeSpan == 0 ? 60 : cacheLifeSpan; //60 minutes default

return client;
});

services.AddSingleton<IBceidApi, BceidApi>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"ExtendedData": {
"inputs": [
"https://gws1.test.bceid.ca/webservices/client/v10/bceidservice.asmx?wsdl"
],
"collectionTypes": [
"System.Array",
"System.Collections.Generic.Dictionary`2"
],
"namespaceMappings": [
"*, BceidService"
],
"references": [
"AutoMapper, {AutoMapper, 12.0.1}",
"C:\\bc-github\\strdss\\server\\StrDss.Service\\bin\\Debug\\net7.0\\StrDss.Common.dll",
"C:\\bc-github\\strdss\\server\\StrDss.Service\\bin\\Debug\\net7.0\\StrDss.Data.dll",
"C:\\bc-github\\strdss\\server\\StrDss.Service\\bin\\Debug\\net7.0\\StrDss.Model.dll",
"CsvHelper, {CsvHelper, 31.0.2}",
"Hangfire.AspNetCore, {Hangfire.AspNetCore, 1.8.6}",
"Hangfire.Core, {Hangfire.Core, 1.8.6}",
"Hangfire.NetCore, {Hangfire.NetCore, 1.8.6}",
"Microsoft.AspNetCore.OpenApi, {Microsoft.AspNetCore.OpenApi, 7.0.10}",
"Microsoft.EntityFrameworkCore, {Microsoft.EntityFrameworkCore, 7.0.11}",
"Microsoft.EntityFrameworkCore.Abstractions, {Microsoft.EntityFrameworkCore.Abstractions, 7.0.11}",
"Microsoft.EntityFrameworkCore.Relational, {Microsoft.EntityFrameworkCore.Relational, 7.0.11}",
"Microsoft.Extensions.Caching.Abstractions, {Microsoft.Extensions.Caching.Abstractions, 7.0.0}",
"Microsoft.Extensions.Caching.Memory, {Microsoft.Extensions.Caching.Memory, 7.0.0}",
"Microsoft.Extensions.Configuration.Abstractions, {Microsoft.Extensions.Configuration.Abstractions, 7.0.0}",
"Microsoft.Extensions.Configuration.Binder, {Microsoft.Extensions.Configuration.Binder, 7.0.4}",
"Microsoft.Extensions.DependencyInjection, {Microsoft.Extensions.DependencyInjection, 7.0.0}",
"Microsoft.Extensions.DependencyInjection.Abstractions, {Microsoft.Extensions.DependencyInjection.Abstractions, 7.0.0}",
"Microsoft.Extensions.FileProviders.Abstractions, {Microsoft.Extensions.FileProviders.Abstractions, 3.0.0}",
"Microsoft.Extensions.Hosting.Abstractions, {Microsoft.Extensions.Hosting.Abstractions, 3.0.0}",
"Microsoft.Extensions.Http, {Microsoft.Extensions.Http, 7.0.0}",
"Microsoft.Extensions.Logging, {Microsoft.Extensions.Logging, 7.0.0}",
"Microsoft.Extensions.Logging.Abstractions, {Microsoft.Extensions.Logging.Abstractions, 7.0.0}",
"Microsoft.Extensions.Options, {Microsoft.Extensions.Options, 7.0.0}",
"Microsoft.Extensions.Primitives, {Microsoft.Extensions.Primitives, 7.0.0}",
"Microsoft.OpenApi, {Microsoft.OpenApi, 1.4.3}",
"NetTopologySuite, {NetTopologySuite, 2.5.0}",
"NetTopologySuite.Features, {NetTopologySuite.Features, 2.0.0}",
"NetTopologySuite.IO.GeoJSON, {NetTopologySuite.IO.GeoJSON, 4.0.0}",
"NetTopologySuite.IO.PostGis, {NetTopologySuite.IO.PostGis, 2.1.0}",
"Newtonsoft.Json, {Newtonsoft.Json, 13.0.1}",
"Npgsql, {Npgsql, 7.0.6}",
"Npgsql.EntityFrameworkCore.PostgreSQL, {Npgsql.EntityFrameworkCore.PostgreSQL, 7.0.11}",
"Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite, {Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite, 7.0.11}",
"Npgsql.NetTopologySuite, {Npgsql.NetTopologySuite, 7.0.6}",
"System.Linq.Dynamic.Core, {System.Linq.Dynamic.Core, 1.3.7}"
],
"targetFramework": "net7.0",
"typeReuseMode": "All"
}
}
Loading

0 comments on commit dd6c908

Please sign in to comment.