Skip to content

Commit e52c59f

Browse files
authored
Merge pull request #156 from TechnologyEnhancedLearning/release-v1.4.1-FlaxLily
Release v1.4.1 flax lily To Test
2 parents d0c1290 + 08fe2fe commit e52c59f

File tree

19 files changed

+153
-32
lines changed

19 files changed

+153
-32
lines changed

Auth/LearningHub.Nhs.Auth.Tests/LearningHub.Nhs.Auth.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
<ItemGroup>
12-
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.8" />
12+
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
1313
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.33" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
1515
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="17.12.0" />

Auth/LearningHub.Nhs.Auth/Controllers/AccountController.cs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Net;
77
using System.Threading.Tasks;
8+
using Azure.Core;
89
using elfhHub.Nhs.Models.Common;
910
using elfhHub.Nhs.Models.Enums;
1011
using IdentityModel;
@@ -22,9 +23,11 @@
2223
using LearningHub.Nhs.Models.Common;
2324
using Microsoft.AspNetCore.Authentication;
2425
using Microsoft.AspNetCore.Authorization;
26+
using Microsoft.AspNetCore.Http;
2527
using Microsoft.AspNetCore.Mvc;
2628
using Microsoft.Extensions.Logging;
2729
using Microsoft.Extensions.Options;
30+
using UAParser;
2831

2932
/// <summary>
3033
/// Account Controller operations.
@@ -163,34 +166,44 @@ await this.interaction.GrantConsentAsync(
163166

164167
if (loginResult.IsAuthenticated)
165168
{
166-
await this.SignInUser(userId, model.Username.Trim(), model.RememberLogin, context.Parameters["ext_referer"]);
167-
168-
if (context != null)
169+
var uaParser = Parser.GetDefault();
170+
var clientInfo = uaParser.Parse(this.Request.Headers["User-Agent"]);
171+
var result = await this.UserService.CheckUserHasAnActiveSessionAsync(userId);
172+
if (result.Items.Count == 0 || result.Items[0].BrowserName == clientInfo.UA.Family)
169173
{
170-
if (await this.ClientStore.IsPkceClientAsync(context.Client.ClientId))
174+
await this.SignInUser(userId, model.Username.Trim(), model.RememberLogin, context.Parameters["ext_referer"]);
175+
176+
if (context != null)
171177
{
172-
// if the client is PKCE then we assume it's native, so this change in how to
173-
// return the response is for better UX for the end user.
174-
return this.View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
178+
if (await this.ClientStore.IsPkceClientAsync(context.Client.ClientId))
179+
{
180+
// if the client is PKCE then we assume it's native, so this change in how to
181+
// return the response is for better UX for the end user.
182+
return this.View("Redirect", new RedirectViewModel { RedirectUrl = model.ReturnUrl });
183+
}
184+
185+
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
186+
return this.Redirect(model.ReturnUrl);
175187
}
176188

177-
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
178-
return this.Redirect(model.ReturnUrl);
179-
}
180-
181-
// request for a local page
182-
if (this.Url.IsLocalUrl(model.ReturnUrl))
183-
{
184-
return this.Redirect(model.ReturnUrl);
185-
}
186-
else if (string.IsNullOrEmpty(model.ReturnUrl))
187-
{
188-
return this.Redirect("~/");
189+
// request for a local page
190+
if (this.Url.IsLocalUrl(model.ReturnUrl))
191+
{
192+
return this.Redirect(model.ReturnUrl);
193+
}
194+
else if (string.IsNullOrEmpty(model.ReturnUrl))
195+
{
196+
return this.Redirect("~/");
197+
}
198+
else
199+
{
200+
// user might have clicked on a malicious link - should be logged
201+
throw new Exception("invalid return URL");
202+
}
189203
}
190204
else
191205
{
192-
// user might have clicked on a malicious link - should be logged
193-
throw new Exception("invalid return URL");
206+
return this.View("AlreadyActiveSession");
194207
}
195208
}
196209
else if (userId > 0)

Auth/LearningHub.Nhs.Auth/Interfaces/IUserService.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ public interface IUserService
114114
/// </returns>
115115
Task StoreUserHistoryAsync(UserHistoryViewModel userHistory);
116116

117+
/// <summary>
118+
/// check user has an laredy active session.
119+
/// </summary>
120+
/// <param name="userId">The userId.</param>
121+
/// <returns>The <see cref="Task"/>.</returns>
122+
Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasAnActiveSessionAsync(int userId);
123+
117124
/// <summary>
118125
/// The store user history async.
119126
/// </summary>

Auth/LearningHub.Nhs.Auth/LearningHub.Nhs.Auth.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Blobs" Version="1.4.0" />
102102
<PackageReference Include="Azure.Extensions.AspNetCore.DataProtection.Keys" Version="1.3.0" />
103103
<PackageReference Include="Azure.Identity" Version="1.13.2" />
104-
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.8" />
104+
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
105105
<PackageReference Include="FluentValidation" Version="11.11.0" />
106106
<PackageReference Include="IdentityServer4" Version="4.1.2" />
107107
<PackageReference Include="IdentityServer4.Contrib.RedisStore" Version="4.0.0" />

Auth/LearningHub.Nhs.Auth/Services/UserService.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,5 +243,29 @@ public async Task StoreUserHistoryAsync(UserHistoryViewModel userHistory)
243243
}
244244
}
245245
}
246+
247+
/// <inheritdoc/>
248+
public async Task<PagedResultSet<UserHistoryViewModel>> CheckUserHasAnActiveSessionAsync(int userId)
249+
{
250+
PagedResultSet<UserHistoryViewModel> userHistoryViewModel = new PagedResultSet<UserHistoryViewModel>();
251+
252+
var client = this.UserApiHttpClient.GetClient();
253+
var request = $"UserHistory/CheckUserHasActiveSession/{userId}";
254+
var response = await client.GetAsync(request).ConfigureAwait(false);
255+
256+
if (response.IsSuccessStatusCode)
257+
{
258+
var result = await response.Content.ReadAsStringAsync();
259+
userHistoryViewModel = JsonConvert.DeserializeObject<PagedResultSet<UserHistoryViewModel>>(result);
260+
}
261+
else if (response.StatusCode == HttpStatusCode.Unauthorized
262+
||
263+
response.StatusCode == HttpStatusCode.Forbidden)
264+
{
265+
throw new Exception("AccessDenied");
266+
}
267+
268+
return userHistoryViewModel;
269+
}
246270
}
247271
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@{
2+
ViewData["Title"] = "Already active session";
3+
}
4+
<div class="bg-white">
5+
<div class="nhsuk-width-container app-width-container">
6+
<div class="nhsuk-grid-row">
7+
<div class="nhsuk-grid-column-full nhsuk-u-padding-top-9 nhsuk-u-padding-bottom-7">
8+
<h1 class="nhsuk-heading-xl"> @ViewData["Title"]</h1>
9+
<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>
10+
<p>If you have any questions, please contact the <a href="@ViewBag.SupportFormUrl" target="_blank">support team</a>.</p>
11+
<p>@DateTimeOffset.Now.ToString("d MMMM yyyy HH:mm:ss")</p>
12+
</div>
13+
</div>
14+
</div>
15+
</div>

LearningHub.Nhs.UserApi.Repository.Interface/IUserHistoryRepository.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,12 @@ public interface IUserHistoryRepository
5959
/// The <see cref="Task"/>.
6060
/// </returns>
6161
Task<UserHistoryStoredProcResults> GetPagedByUserIdAsync(int userId, int startPage, int pageSize);
62+
63+
/// <summary>
64+
/// Check user has an active login session.
65+
/// </summary>
66+
/// <param name="userId">The userId.</param>
67+
/// <returns>The <see cref="Task"/>.</returns>
68+
Task<UserHistoryStoredProcResults> CheckUserHasActiveSessionAsync(int userId);
6269
}
6370
}

LearningHub.Nhs.UserApi.Repository.Interface/LearningHub.Nhs.UserApi.Repository.Interface.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
11+
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
1212
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
1313
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
1414
<PrivateAssets>all</PrivateAssets>

LearningHub.Nhs.UserApi.Repository/LearningHub.Nhs.UserApi.Repository.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.9" />
11+
<PackageReference Include="elfhHub.Nhs.Models" Version="3.0.10" />
1212
<PackageReference Include="LearningHub.Nhs.Models" Version="3.0.46" />
1313
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
1414
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />

LearningHub.Nhs.UserApi.Repository/UserHistoryRepository.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using LearningHub.Nhs.UserApi.Repository.Interface;
1010
using Microsoft.Data.SqlClient;
1111
using Microsoft.EntityFrameworkCore;
12+
using Newtonsoft.Json.Linq;
1213

1314
/// <summary>
1415
/// The user history repository.
@@ -66,11 +67,13 @@ public async Task CreateAsync(int userId, int tenantId, UserHistoryViewModel use
6667
new SqlParameter("@LoginIP", SqlDbType.VarChar) { Value = userHistoryVM.LoginIP ?? (object)DBNull.Value },
6768
new SqlParameter("@LoginSuccessFul", SqlDbType.Bit) { Value = userHistoryVM.LoginSuccessFul ?? (object)DBNull.Value },
6869
new SqlParameter("@TenantId", SqlDbType.Int) { Value = tenantId },
70+
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 },
71+
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 },
6972
new SqlParameter("@AmendUserId", SqlDbType.Int) { Value = userId },
7073
new SqlParameter("@AmendDate", SqlDbType.DateTimeOffset) { Value = DateTimeOffset.Now },
7174
};
7275

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

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

99102
return retVal;
100103
}
104+
105+
/// <inheritdoc/>
106+
public async Task<UserHistoryStoredProcResults> CheckUserHasActiveSessionAsync(int userId)
107+
{
108+
try
109+
{
110+
var retVal = new UserHistoryStoredProcResults();
111+
var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = userId };
112+
113+
var result = await this.DbContext.Set<UserHistoryStoredProcResult>().FromSqlRaw(
114+
"dbo.proc_ActiveLearningHubUserbyId @p0", param0).AsNoTracking().ToListWithNoLockAsync();
115+
retVal.Results = result;
116+
return retVal;
117+
}
118+
catch (Exception ex)
119+
{
120+
return null;
121+
}
122+
}
101123
}
102124
}

0 commit comments

Comments
 (0)