Skip to content
Merged
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
Expand Up @@ -9,7 +9,7 @@


<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.8" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.33" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="17.12.0" />
Expand Down
55 changes: 34 additions & 21 deletions Auth/LearningHub.Nhs.Auth/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Azure.Core;
using elfhHub.Nhs.Models.Common;
using elfhHub.Nhs.Models.Enums;
using IdentityModel;
Expand All @@ -22,9 +23,11 @@
using LearningHub.Nhs.Models.Common;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using UAParser;

/// <summary>
/// Account Controller operations.
Expand Down Expand Up @@ -163,34 +166,44 @@ await this.interaction.GrantConsentAsync(

if (loginResult.IsAuthenticated)
{
await this.SignInUser(userId, model.Username.Trim(), model.RememberLogin, context.Parameters["ext_referer"]);

if (context != null)
var uaParser = Parser.GetDefault();
var clientInfo = uaParser.Parse(this.Request.Headers["User-Agent"]);
var result = await this.UserService.CheckUserHasAnActiveSessionAsync(userId);
if (result.Items.Count == 0 || result.Items[0].BrowserName == clientInfo.UA.Family)
{
if (await this.ClientStore.IsPkceClientAsync(context.Client.ClientId))
await this.SignInUser(userId, model.Username.Trim(), model.RememberLogin, context.Parameters["ext_referer"]);

if (context != null)
{
// if the client is PKCE then we assume it's native, so this change in how to
// return the response is for better UX for the end user.
return this.View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
if (await this.ClientStore.IsPkceClientAsync(context.Client.ClientId))
{
// if the client is PKCE then we assume it's native, so this change in how to
// return the response is for better UX for the end user.
return this.View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
}

// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return this.Redirect(model.ReturnUrl);
}

// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
return this.Redirect(model.ReturnUrl);
}

// request for a local page
if (this.Url.IsLocalUrl(model.ReturnUrl))
{
return this.Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return this.Redirect("~/");
// request for a local page
if (this.Url.IsLocalUrl(model.ReturnUrl))
{
return this.Redirect(model.ReturnUrl);
}
else if (string.IsNullOrEmpty(model.ReturnUrl))
{
return this.Redirect("~/");
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
}
}
else
{
// user might have clicked on a malicious link - should be logged
throw new Exception("invalid return URL");
return this.View("AlreadyActiveSession");
}
}
else if (userId > 0)
Expand Down
7 changes: 7 additions & 0 deletions Auth/LearningHub.Nhs.Auth/Interfaces/IUserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ public interface IUserService
/// </returns>
Task StoreUserHistoryAsync(UserHistoryViewModel userHistory);

/// <summary>
/// check user has an laredy active session.
/// </summary>
/// <param name="userId">The userId.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasAnActiveSessionAsync(int userId);

/// <summary>
/// The store user history async.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Auth/LearningHub.Nhs.Auth/LearningHub.Nhs.Auth.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.4.0" />
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.3.0" />
<PackageReference Include="Azure.Identity" Version="1.13.2" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.8" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="FluentValidation" Version="11.11.0" />
<PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="IdentityServer4.Contrib.RedisStore" Version="4.0.0" />
Expand Down
24 changes: 24 additions & 0 deletions Auth/LearningHub.Nhs.Auth/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,29 @@ public async Task StoreUserHistoryAsync(UserHistoryViewModel userHistory)
}
}
}

/// <inheritdoc/>
public async Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasAnActiveSessionAsync(int userId)
{
PagedResultSet<UserHistoryViewModel> userHistoryViewModel = new PagedResultSet<UserHistoryViewModel>();

var client = this.UserApiHttpClient.GetClient();
var request = $"UserHistory/CheckUserHasActiveSession/{userId}";
var response = await client.GetAsync(request).ConfigureAwait(false);

if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync();
userHistoryViewModel = JsonConvert.DeserializeObject<PagedResultSet<UserHistoryViewModel>>(result);
}
else if (response.StatusCode == HttpStatusCode.Unauthorized
||
response.StatusCode == HttpStatusCode.Forbidden)
{
throw new Exception("AccessDenied");
}

return userHistoryViewModel;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@{
ViewData["Title"] = "Already active session";
}
<div class="bg-white">
<div class="nhsuk-width-container app-width-container">
<div class="nhsuk-grid-row">
<div class="nhsuk-grid-column-full nhsuk-u-padding-top-9 nhsuk-u-padding-bottom-7">
<h1 class="nhsuk-heading-xl"> @ViewData["Title"]</h1>
<p>You are already logged in from another browser. Please continue using the same browser or close the existing session and try again with a new one.</p>
<p>If you have any questions, please contact the <a href="@ViewBag.SupportFormUrl" target="_blank">support team</a>.</p>
<p>@DateTimeOffset.Now.ToString("d MMMM yyyy HH:mm:ss")</p>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,12 @@ public interface IUserHistoryRepository
/// The <see cref="Task"/>.
/// </returns>
Task<UserHistoryStoredProcResults> GetPagedByUserIdAsync(int userId, int startPage, int pageSize);

/// <summary>
/// Check user has an active login session.
/// </summary>
/// <param name="userId">The userId.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<UserHistoryStoredProcResults> CheckUserHasActiveSessionAsync(int userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
Expand Down
24 changes: 23 additions & 1 deletion LearningHub.Nhs.UserApi.Repository/UserHistoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using LearningHub.Nhs.UserApi.Repository.Interface;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;

/// <summary>
/// The user history repository.
Expand Down Expand Up @@ -66,11 +67,13 @@ public async Task CreateAsync(int userId, int tenantId, UserHistoryViewModel use
new SqlParameter("@LoginIP", SqlDbType.VarChar) { Value = userHistoryVM.LoginIP ?? (object)DBNull.Value },
new SqlParameter("@LoginSuccessFul", SqlDbType.Bit) { Value = userHistoryVM.LoginSuccessFul ?? (object)DBNull.Value },
new SqlParameter("@TenantId", SqlDbType.Int) { Value = tenantId },
new SqlParameter("@SessionId", SqlDbType.VarChar) { Value = (userHistoryVM.UserHistoryTypeId == 0 && userHistoryVM.Detail == "User logged on. Source of auth: LearningHub.Nhs.Auth Account\\Login") ? userHistoryVM.SessionId : (object)DBNull.Value },
new SqlParameter("@IsActive", SqlDbType.Bit) { Value = (userHistoryVM.UserHistoryTypeId == 0 && userHistoryVM.Detail == "User logged on. Source of auth: LearningHub.Nhs.Auth Account\\Login") ? userHistoryVM.IsActive : (object)DBNull.Value },
new SqlParameter("@AmendUserId", SqlDbType.Int) { Value = userId },
new SqlParameter("@AmendDate", SqlDbType.DateTimeOffset) { Value = DateTimeOffset.Now },
};

string sql = "proc_UserHistoryInsert @UserId, @UserHistoryTypeId, @Detail, @UserAgent, @BrowserName, @BrowserVersion, @UrlReferer, @LoginIP, @LoginSuccessFul, @TenantId, @AmendUserId, @AmendDate";
string sql = "proc_UserHistoryInsert @UserId, @UserHistoryTypeId, @Detail, @UserAgent, @BrowserName, @BrowserVersion, @UrlReferer, @LoginIP, @LoginSuccessFul, @TenantId, @SessionId, @IsActive, @AmendUserId, @AmendDate";

await this.DbContext.Database.ExecuteSqlRawAsync(sql, sqlParams);
}
Expand Down Expand Up @@ -98,5 +101,24 @@ public async Task<UserHistoryStoredProcResults> GetPagedByUserIdAsync(int userId

return retVal;
}

/// <inheritdoc/>
public async Task<UserHistoryStoredProcResults> CheckUserHasActiveSessionAsync(int userId)
{
try
{
var retVal = new UserHistoryStoredProcResults();
var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = userId };

var result = await this.DbContext.Set<UserHistoryStoredProcResult>().FromSqlRaw(
"dbo.proc_ActiveLearningHubUserbyId @p0", param0).AsNoTracking().ToListWithNoLockAsync();
retVal.Results = result;
return retVal;
}
catch (Exception ex)
{
return null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,12 @@ public interface IUserHistoryService
/// The <see cref="Task"/>.
/// </returns>
Task<PagedResultSet<UserHistoryViewModel>> GetUserHistoryPageAsync(int page, int pageSize, string sortColumn = "", string sortDirection = "", string presetFilter = "", string filter = "");

/// <summary>
/// Check user has an active login session.
/// </summary>
/// <param name="userId">The userId.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasActiveSessionAsync(int userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="EntityFrameworkCore.Testing.Moq" Version="5.0.0" />
<PackageReference Include="LearningHub.Nhs.Caching" Version="2.0.0" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.3.0" />
Expand Down
13 changes: 13 additions & 0 deletions LearningHub.Nhs.UserApi.Services/UserHistoryService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace LearningHub.Nhs.UserApi.Services
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -56,6 +57,8 @@ public async Task<LearningHubValidationResult> CreateAsync(UserHistoryViewModel

if (retVal.IsValid)
{
userHistoryVM.SessionId = Guid.NewGuid().ToString();
userHistoryVM.IsActive = true;
await this.userHistoryRepository.CreateAsync(userHistoryVM.UserId, this.settings.LearningHubTenantId, userHistoryVM);
}

Expand Down Expand Up @@ -99,6 +102,16 @@ public async Task<PagedResultSet<UserHistoryViewModel>> GetUserHistoryPageAsync(
return result;
}

/// <inheritdoc/>
public async Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasActiveSessionAsync(int userId)
{
PagedResultSet<UserHistoryViewModel> result = new PagedResultSet<UserHistoryViewModel>();
var userHistory = await this.userHistoryRepository.CheckUserHasActiveSessionAsync(userId);
userHistory.Results.ForEach(x => x.UserAgent = this.ParseUserAgentString(x.UserAgent));
result.Items = this.mapper.Map<List<UserHistoryViewModel>>(userHistory.Results);
return result;
}

private string ParseUserAgentString(string userAgent)
{
string retVal = string.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Moq" Version="4.20.72" />
Expand Down
13 changes: 13 additions & 0 deletions LearningHub.Nhs.UserApi/Controllers/UserHistoryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ public async Task<IActionResult> GetUserHistoryPageAsync(int page, int pageSize,
return this.Ok(pagedResultSet);
}

/// <summary>
/// Check the user has an active login session.
/// </summary>
/// <param name="userId">The UserId.</param>
/// <returns>The <see cref="Task"/>.</returns>
[HttpGet]
[Route("CheckUserHasActiveSession/{userId}")]
public async Task<IActionResult> CheckUserHasActiveSessionAsync(int userId)
{
PagedResultSet<UserHistoryViewModel> pagedResultSet = await this.userHistoryService.CheckUserHasActiveSessionAsync(userId);
return this.Ok(pagedResultSet);
}

/// <summary>
/// Create a UserHistory.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion LearningHub.Nhs.UserApi/LearningHub.Nhs.UserApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="LearningHub.Nhs.Caching" Version="2.0.0" />
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
Expand Down
Loading