Skip to content

Commit

Permalink
Fix for database context allowing post authentication to upsert user
Browse files Browse the repository at this point in the history
ChrisJWoodcock committed Jul 6, 2022
1 parent 704b078 commit ef0babe
Showing 10 changed files with 92 additions and 103 deletions.
33 changes: 16 additions & 17 deletions src/SFA.DAS.EmployerFinance.Web/App_Start/FilterConfig.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
using System.Web.Mvc;
using SFA.DAS.Authorization.Mvc.Extensions;
using SFA.DAS.EmployerFinance.Web.Filters;
using System.Web.Mvc;
using SFA.DAS.Authorization.Mvc.Extensions;
using SFA.DAS.EmployerFinance.Web.Filters;
using SFA.DAS.UnitOfWork.Mvc.Extensions;

namespace SFA.DAS.EmployerFinance.Web
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.AddUnitOfWorkFilter();
filters.AddAuthorizationFilter();
filters.AddUnauthorizedAccessExceptionFilter();
filters.Add(new AnalyticsFilter());
filters.Add(new UpsertUserFilter());
}
}
}
namespace SFA.DAS.EmployerFinance.Web
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.AddUnitOfWorkFilter();
filters.AddAuthorizationFilter();
filters.AddUnauthorizedAccessExceptionFilter();
filters.Add(new AnalyticsFilter());
}
}
}
63 changes: 0 additions & 63 deletions src/SFA.DAS.EmployerFinance.Web/Filters/UpsertUserFilter.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using MediatR;
using SFA.DAS.EmployerFinance.Commands.UpsertRegisteredUser;
using SFA.DAS.NLog.Logger;
using System;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerFinance.Web.Orchestrators
{
public class AuthenticationOrchestrator
{
private readonly IMediator _mediator;

public AuthenticationOrchestrator(IMediator mediator)
{
if (mediator == null)
throw new ArgumentNullException(nameof(mediator));
_mediator = mediator;
}

public async Task SaveIdentityAttributes(string userRef, string email, string firstName, string lastName)
{
await _mediator.SendAsync(new UpsertRegisteredUserCommand
{
EmailAddress = email,
UserRef = userRef,
LastName = lastName,
FirstName = firstName
});
}
}
}
Original file line number Diff line number Diff line change
@@ -180,7 +180,6 @@
<Compile Include="Extensions\HtmlHelperExtensions.cs" />
<Compile Include="Extensions\TimeSpanExtensions.cs" />
<Compile Include="Extensions\UrlHelperExtensions.cs" />
<Compile Include="Filters\UpsertUserFilter.cs" />
<Compile Include="Filters\LevyEmployerTypeOnly.cs" />
<Compile Include="Filters\AnalyticsFilter.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
@@ -195,6 +194,7 @@
<Compile Include="Mappings\TransferMappings.cs" />
<Compile Include="NServiceBusStartup.cs" />
<Compile Include="OrchestratorResponse.cs" />
<Compile Include="Orchestrators\AuthenticationOrchestrator.cs" />
<Compile Include="Orchestrators\EmployerAccountTransactionsOrchestrator.cs" />
<Compile Include="Orchestrators\TransfersOrchestrator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
18 changes: 11 additions & 7 deletions src/SFA.DAS.EmployerFinance.Web/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using MediatR;
using Microsoft.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using NLog;
using Owin;
using SFA.DAS.Authentication;
using SFA.DAS.EmployerFinance.Commands.UpsertRegisteredUser;
using SFA.DAS.EmployerFinance.Configuration;
using SFA.DAS.EmployerFinance.Data;
using SFA.DAS.EmployerFinance.Web;
using SFA.DAS.EmployerFinance.Web.App_Start;
using SFA.DAS.EmployerFinance.Web.Authentication;
using SFA.DAS.EmployerFinance.Web.Filters;
using SFA.DAS.EmployerFinance.Web.Orchestrators;
using SFA.DAS.EmployerUsers.WebClientComponents;
using SFA.DAS.OidcMiddleware;
using System;
@@ -21,7 +20,6 @@
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

[assembly: OwinStartup(typeof(Startup))]
@@ -34,6 +32,7 @@ public class Startup

public void Configuration(IAppBuilder app)
{
var authenticationOrchestrator = StructuremapMvc.StructureMapDependencyScope.Container.GetInstance<AuthenticationOrchestrator>();
var config = StructuremapMvc.StructureMapDependencyScope.Container.GetInstance<EmployerFinanceConfiguration>();
var constants = new Constants(config.Identity);
var urlHelper = new UrlHelper();
@@ -64,7 +63,7 @@ public void Configuration(IAppBuilder app)
TokenValidationMethod = config.Identity.UseCertificate ? TokenValidationMethod.SigningKey : TokenValidationMethod.BinarySecret,
AuthenticatedCallback = identity =>
{
PostAuthentiationAction(identity, constants);
PostAuthentiationAction(identity, authenticationOrchestrator, constants);
}
});

@@ -104,18 +103,23 @@ private static Func<X509Certificate2> GetSigningCertificate(bool useCertificate)
};
}

private static void PostAuthentiationAction(ClaimsIdentity identity, Constants constants)
private static void PostAuthentiationAction(ClaimsIdentity identity, AuthenticationOrchestrator authenticationOrchestrator, Constants constants)
{
Logger.Info("Retrieving claims from OIDC server.");

var userRef = identity.Claims.FirstOrDefault(claim => claim.Type == constants.Id())?.Value;
var email = identity.Claims.FirstOrDefault(claim => claim.Type == constants.Email())?.Value;
var firstName = identity.Claims.FirstOrDefault(claim => claim.Type == constants.GivenName())?.Value;
var lastName = identity.Claims.FirstOrDefault(claim => claim.Type == constants.FamilyName())?.Value;

Logger.Info($"Retrieved claims from OIDC server for user with external ID '{userRef}'.");

identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identity.Claims.First(c => c.Type == constants.Id()).Value));
identity.AddClaim(new Claim(ClaimTypes.Name, identity.Claims.First(c => c.Type == constants.DisplayName()).Value));
identity.AddClaim(new Claim("sub", identity.Claims.First(c => c.Type == constants.Id()).Value));
identity.AddClaim(new Claim("email", identity.Claims.First(c => c.Type == constants.Email()).Value));

Task.Run(async () => await authenticationOrchestrator.SaveIdentityAttributes(userRef, email, firstName, lastName)).Wait();
}
}

Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

namespace SFA.DAS.EmployerFinance.Commands.UpsertRegisteredUser
{
public class UpsertRegisteredUserCommand : IRequest
public class UpsertRegisteredUserCommand : IAsyncRequest
{
public string UserRef { get; set; }
public string FirstName { get; set; }
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
using MediatR;
using SFA.DAS.EmployerFinance.Data;
using SFA.DAS.EmployerFinance.Models.UserProfile;
using SFA.DAS.NLog.Logger;
using SFA.DAS.Validation;
using System;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerFinance.Commands.UpsertRegisteredUser
{
public class UpsertRegisteredUserCommandHandler : RequestHandler<UpsertRegisteredUserCommand>
public class UpsertRegisteredUserCommandHandler : AsyncRequestHandler<UpsertRegisteredUserCommand>
{
private readonly IValidator<UpsertRegisteredUserCommand> _validator;
private readonly IUserAccountRepository _userRepository;
private readonly ILog _logger;
private readonly IUserRepository _userRepository;

public UpsertRegisteredUserCommandHandler(
IValidator<UpsertRegisteredUserCommand> validator,
IUserAccountRepository userRepository)
ILog logger,
IUserRepository userRepository)
{
_validator = validator;
_logger = logger;
_userRepository = userRepository;
}

protected override void HandleCore(UpsertRegisteredUserCommand message)
protected override async Task HandleCore(UpsertRegisteredUserCommand message)
{
var validationResult = _validator.Validate(message);

if (!validationResult.IsValid()) throw new InvalidRequestException(validationResult.ValidationDictionary);

_userRepository.Upsert(new User
await _userRepository.Upsert(new User
{
Ref = new Guid(message.UserRef),
Email = message.EmailAddress,
FirstName = message.FirstName,
LastName = message.LastName,
CorrelationId = message.CorrelationId
});

_logger.Info($"Upserted user with email={message.EmailAddress}, userRef={message.UserRef}, lastName={message.LastName}, firstName={message.FirstName}");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using SFA.DAS.EmployerFinance.Models.UserProfile;
using System.Threading.Tasks;

namespace SFA.DAS.EmployerFinance.Data
{
public interface IUserAccountRepository
public interface IUserRepository
{
void Upsert(User user);
Task Upsert(User user);
}
}
Original file line number Diff line number Diff line change
@@ -9,17 +9,17 @@

namespace SFA.DAS.EmployerFinance.Data
{
public class UserAccountRepository : BaseRepository, IUserAccountRepository
public class UserRepository : BaseRepository, IUserRepository
{
private readonly Lazy<EmployerFinanceDbContext> _db;

public UserAccountRepository(EmployerFinanceConfiguration configuration, ILog logger, Lazy<EmployerFinanceDbContext> db)
public UserRepository(EmployerFinanceConfiguration configuration, ILog logger, Lazy<EmployerFinanceDbContext> db)
: base(configuration.DatabaseConnectionString, logger)
{
_db = db;
}

public void Upsert(User user)
public async Task Upsert(User user)
{
var parameters = new DynamicParameters();

@@ -29,10 +29,10 @@ public void Upsert(User user)
parameters.Add("@lastName", user.LastName, DbType.String);
parameters.Add("@correlationId", user.CorrelationId, DbType.String);

_db.Value.Database.Connection.Execute(
await _db.Value.Database.Connection.ExecuteAsync(
sql: "[employer_financial].[UpsertUser] @userRef, @email, @firstName, @lastName, @correlationId",
param: parameters,
_db.Value.Database.CurrentTransaction.UnderlyingTransaction,
transaction: _db.Value.Database.CurrentTransaction.UnderlyingTransaction,
commandType: CommandType.Text);
}
}
15 changes: 13 additions & 2 deletions src/SFA.DAS.EmployerFinance/DependencyResolution/DataRegistry.cs
Original file line number Diff line number Diff line change
@@ -42,9 +42,20 @@ private EmployerFinanceDbContext GetDbContext(IContext context)
var unitOfWorkContext = context.GetInstance<IUnitOfWorkContext>();
var clientSession = unitOfWorkContext.Find<IClientOutboxTransaction>();
var serverSession = unitOfWorkContext.Find<SynchronizedStorageSession>();
var sqlSession = clientSession?.GetSqlSession() ?? serverSession.GetSqlSession();
var sqlSession = clientSession?.GetSqlSession() ?? serverSession?.GetSqlSession();

return new EmployerFinanceDbContext(sqlSession.Connection, sqlSession.Transaction);
if(sqlSession != null)
{
return new EmployerFinanceDbContext(sqlSession.Connection, sqlSession.Transaction);
}
else
{
// during the owin setup the NServiceBus storage session is not available so
// the context cannot be constructed using the unit of work, this would mean
// that a message cannot be published atomically with a database update
var dbConnection = context.GetInstance<DbConnection>();
return new EmployerFinanceDbContext(dbConnection);
}
}

private string GetConnectionString(IContext context)

0 comments on commit ef0babe

Please sign in to comment.