Skip to content

Commit 4ccfe6e

Browse files
committed
Configuring OpenID Connect Authentication with moodle user id
1 parent 0c3fa62 commit 4ccfe6e

File tree

8 files changed

+340
-1
lines changed

8 files changed

+340
-1
lines changed

Auth/LearningHub.Nhs.Auth/Configuration/ServiceMappings.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,22 @@ public static void AddServiceMappings(this IServiceCollection services, IConfigu
4040
ServerCertificateCustomValidationCallback =
4141
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
4242
});
43+
44+
services.AddHttpClient<IMoodleHttpClient, MoodleHttpClient>()
45+
.ConfigurePrimaryHttpMessageHandler(
46+
() => new HttpClientHandler
47+
{
48+
ServerCertificateCustomValidationCallback =
49+
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
50+
});
4351
}
4452
else
4553
{
4654
services.AddHttpClient<IUserApiHttpClient, UserApiHttpClient>();
55+
services.AddHttpClient<IMoodleHttpClient, MoodleHttpClient>();
4756
}
4857

58+
services.AddScoped<IMoodleApiService, MoodleApiService>();
4959
services.AddDistributedMemoryCache();
5060
services.AddScoped<IExternalSystemService, ExternalSystemService>();
5161
services.AddTransient<IRegistrationService, RegistrationService>();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace LearningHub.Nhs.Auth.Interfaces
2+
{
3+
using System.Threading.Tasks;
4+
5+
/// <summary>
6+
/// IMoodleApiService.
7+
/// </summary>
8+
public interface IMoodleApiService
9+
{
10+
/// <summary>
11+
/// GetResourcesAsync.
12+
/// </summary>
13+
/// <param name="currentUserId">The current User Id.</param>
14+
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
15+
Task<int> GetMoodleUserIdByUsernameAsync(int currentUserId);
16+
}
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace LearningHub.Nhs.Auth.Interfaces
2+
{
3+
using System.Net.Http;
4+
using System.Threading.Tasks;
5+
6+
/// <summary>
7+
/// The Moodle Http Client interface.
8+
/// </summary>
9+
public interface IMoodleHttpClient
10+
{
11+
/// <summary>
12+
/// The get cient async.
13+
/// </summary>
14+
/// <returns>The <see cref="Task"/>.</returns>
15+
Task<HttpClient> GetClient();
16+
17+
/// <summary>
18+
/// GetDefaultParameters.
19+
/// </summary>
20+
/// <returns>defaultParameters.</returns>
21+
string GetDefaultParameters();
22+
}
23+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
namespace LearningHub.Nhs.Auth.Models
2+
{
3+
using System.Collections.Generic;
4+
5+
/// <summary>
6+
/// MoodleUserResponseViewModel.
7+
/// </summary>
8+
public class MoodleUserResponseViewModel
9+
{
10+
/// <summary>
11+
/// Gets or sets the list of users.
12+
/// </summary>
13+
public List<MoodleUser> Users { get; set; }
14+
15+
/// <summary>
16+
/// Gets or sets the warnings.
17+
/// </summary>
18+
public List<object> Warnings { get; set; }
19+
20+
/// <summary>
21+
/// MoodleUser.
22+
/// </summary>
23+
public class MoodleUser
24+
{
25+
/// <summary>
26+
/// Gets or sets the user ID.
27+
/// </summary>
28+
public int Id { get; set; }
29+
30+
/// <summary>
31+
/// Gets or sets the username.
32+
/// </summary>
33+
public string Username { get; set; }
34+
35+
/// <summary>
36+
/// Gets or sets the first name.
37+
/// </summary>
38+
public string FirstName { get; set; }
39+
40+
/// <summary>
41+
/// Gets or sets the last name.
42+
/// </summary>
43+
public string LastName { get; set; }
44+
45+
/// <summary>
46+
/// Gets or sets the full name.
47+
/// </summary>
48+
public string FullName { get; set; }
49+
50+
/// <summary>
51+
/// Gets or sets the email.
52+
/// </summary>
53+
public string Email { get; set; }
54+
55+
/// <summary>
56+
/// Gets or sets the department.
57+
/// </summary>
58+
public string Department { get; set; }
59+
60+
/// <summary>
61+
/// Gets or sets the first access timestamp.
62+
/// </summary>
63+
public long FirstAccess { get; set; }
64+
65+
/// <summary>
66+
/// Gets or sets the last access timestamp.
67+
/// </summary>
68+
public long LastAccess { get; set; }
69+
70+
/// <summary>
71+
/// Gets or sets the authentication method.
72+
/// </summary>
73+
public string Auth { get; set; }
74+
75+
/// <summary>
76+
/// Gets or sets a value indicating whether the user is suspended.
77+
/// </summary>
78+
public bool Suspended { get; set; }
79+
80+
/// <summary>
81+
/// Gets or sets a value indicating whether the user is confirmed.
82+
/// </summary>
83+
public bool Confirmed { get; set; }
84+
85+
/// <summary>
86+
/// Gets or sets the language.
87+
/// </summary>
88+
public string Lang { get; set; }
89+
90+
/// <summary>
91+
/// Gets or sets the theme.
92+
/// </summary>
93+
public string Theme { get; set; }
94+
95+
/// <summary>
96+
/// Gets or sets the timezone.
97+
/// </summary>
98+
public string Timezone { get; set; }
99+
100+
/// <summary>
101+
/// Gets or sets the mail format.
102+
/// </summary>
103+
public int MailFormat { get; set; }
104+
105+
/// <summary>
106+
/// Gets or sets the forum tracking preference.
107+
/// </summary>
108+
public int TrackForums { get; set; }
109+
110+
/// <summary>
111+
/// Gets or sets the small profile image URL.
112+
/// </summary>
113+
public string ProfileImageUrlSmall { get; set; }
114+
115+
/// <summary>
116+
/// Gets or sets the profile image URL.
117+
/// </summary>
118+
public string ProfileImageUrl { get; set; }
119+
}
120+
}
121+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace LearningHub.Nhs.Auth.Services
2+
{
3+
using System;
4+
using System.Net.Http;
5+
using System.Threading.Tasks;
6+
using LearningHub.Nhs.Auth.Interfaces;
7+
using LearningHub.Nhs.Auth.Models;
8+
using Newtonsoft.Json;
9+
10+
/// <summary>
11+
/// MoodleApiService.
12+
/// </summary>
13+
public class MoodleApiService : IMoodleApiService
14+
{
15+
private readonly IMoodleHttpClient moodleHttpClient;
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="MoodleApiService"/> class.
19+
/// </summary>
20+
/// <param name="moodleHttpClient">moodleHttpClient.</param>
21+
public MoodleApiService(IMoodleHttpClient moodleHttpClient)
22+
{
23+
this.moodleHttpClient = moodleHttpClient;
24+
}
25+
26+
/// <summary>
27+
/// GetMoodleUserIdByUsernameAsync.
28+
/// </summary>
29+
/// <param name="currentUserId">current User Id.</param>
30+
/// <returns>UserId from Moodle.</returns>
31+
public async Task<int> GetMoodleUserIdByUsernameAsync(int currentUserId)
32+
{
33+
int moodleUserId = 0;
34+
string additionalParameters = $"&criteria[0][key]=username&criteria[0][value]={currentUserId}";
35+
string defaultParameters = this.moodleHttpClient.GetDefaultParameters();
36+
37+
var client = await this.moodleHttpClient.GetClient();
38+
39+
string url = $"&wsfunction=core_user_get_users{additionalParameters}";
40+
41+
HttpResponseMessage response = await client.GetAsync("?" + defaultParameters + url);
42+
if (response.IsSuccessStatusCode)
43+
{
44+
var result = response.Content.ReadAsStringAsync().Result;
45+
var viewmodel = JsonConvert.DeserializeObject<MoodleUserResponseViewModel>(result);
46+
47+
foreach (var user in viewmodel.Users)
48+
{
49+
if (user.Username == currentUserId.ToString())
50+
{
51+
moodleUserId = user.Id;
52+
}
53+
}
54+
}
55+
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized ||
56+
response.StatusCode == System.Net.HttpStatusCode.Forbidden)
57+
{
58+
throw new Exception("AccessDenied");
59+
}
60+
61+
return moodleUserId;
62+
}
63+
}
64+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
namespace LearningHub.Nhs.Auth.Services
2+
{
3+
using System;
4+
using System.Net.Http;
5+
using System.Net.Http.Headers;
6+
using System.Threading.Tasks;
7+
using LearningHub.Nhs.Auth.Interfaces;
8+
using Microsoft.Extensions.Configuration;
9+
10+
/// <summary>
11+
/// The moodle http client.
12+
/// </summary>
13+
public class MoodleHttpClient : IMoodleHttpClient, IDisposable
14+
{
15+
private readonly HttpClient httpClient = new ();
16+
private bool initialised = false;
17+
private string moodleAPIBaseUrl;
18+
private string moodleAPIMoodleWSRestFormat;
19+
private string moodleAPIWSToken;
20+
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="MoodleHttpClient"/> class.
23+
/// </summary>
24+
/// <param name="httpClient">httpClient.</param>
25+
/// <param name="config">config.</param>
26+
public MoodleHttpClient(HttpClient httpClient, IConfiguration config)
27+
{
28+
this.httpClient = httpClient;
29+
this.moodleAPIBaseUrl = config["MoodleAPIConfig:BaseUrl"];
30+
this.moodleAPIMoodleWSRestFormat = config["MoodleAPIConfig:MoodleWSRestFormat"];
31+
this.moodleAPIWSToken = config["MoodleAPIConfig:WSToken"];
32+
}
33+
34+
/// <summary>
35+
/// The Get Client method.
36+
/// </summary>
37+
/// <returns>The <see cref="Task"/>.</returns>
38+
public async Task<HttpClient> GetClient()
39+
{
40+
this.Initialise(this.moodleAPIBaseUrl);
41+
return this.httpClient;
42+
}
43+
44+
/// <summary>
45+
/// GetDefaultParameters.
46+
/// </summary>
47+
/// <returns>defaultParameters.</returns>
48+
public string GetDefaultParameters()
49+
{
50+
string defaultParameters = $"wstoken={this.moodleAPIWSToken}"
51+
+ $"&moodlewsrestformat={this.moodleAPIMoodleWSRestFormat}";
52+
53+
return defaultParameters;
54+
}
55+
56+
/// <inheritdoc/>
57+
public void Dispose()
58+
{
59+
this.Dispose(true);
60+
GC.SuppressFinalize(this);
61+
}
62+
63+
/// <summary>
64+
/// The dispoase.
65+
/// </summary>
66+
/// <param name="disposing">disposing.</param>
67+
protected virtual void Dispose(bool disposing)
68+
{
69+
if (disposing)
70+
{
71+
this.httpClient.Dispose();
72+
}
73+
}
74+
75+
private void Initialise(string httpClientUrl)
76+
{
77+
if (this.initialised == false)
78+
{
79+
this.httpClient.BaseAddress = new Uri(httpClientUrl);
80+
this.httpClient.DefaultRequestHeaders.Accept.Clear();
81+
this.httpClient.DefaultRequestHeaders.Accept.Add(
82+
new MediaTypeWithQualityHeaderValue("application/json"));
83+
this.initialised = true;
84+
}
85+
}
86+
}
87+
}

Auth/LearningHub.Nhs.Auth/UserServices/LearningHubProfileService.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ public class LearningHubProfileService : IProfileService
2020
/// <param name="userService">
2121
/// The user service.
2222
/// </param>
23+
/// <param name="moodleApiService">
24+
/// The moodle api service.
25+
/// </param>
2326
/// <param name="logger">
2427
/// The logger.
2528
/// </param>
26-
public LearningHubProfileService(IUserService userService, ILogger<LearningHubProfileService> logger)
29+
public LearningHubProfileService(IUserService userService, IMoodleApiService moodleApiService, ILogger<LearningHubProfileService> logger)
2730
{
2831
this.UserService = userService;
32+
this.MoodleApiService = moodleApiService;
2933
this.Logger = logger;
3034
}
3135

@@ -39,6 +43,11 @@ public LearningHubProfileService(IUserService userService, ILogger<LearningHubPr
3943
/// </summary>
4044
protected IUserService UserService { get; }
4145

46+
/// <summary>
47+
/// Gets the moodle api service.
48+
/// </summary>
49+
protected IMoodleApiService MoodleApiService { get; }
50+
4251
/// <summary>
4352
/// The get profile data async.
4453
/// </summary>
@@ -53,6 +62,8 @@ public async Task GetProfileDataAsync(ProfileDataRequestContext context)
5362
if (context != null)
5463
{
5564
var user = await this.UserService.GetBasicUserByUserIdAsync(context.Subject.GetSubjectId());
65+
var moodleUser = await this.MoodleApiService.GetMoodleUserIdByUsernameAsync(user.Id);
66+
5667
var roleName = await this.UserService.GetUserRoleAsync(user.Id);
5768

5869
var claims = new List<Claim>
@@ -63,6 +74,7 @@ public async Task GetProfileDataAsync(ProfileDataRequestContext context)
6374
new Claim("family_name", user.LastName),
6475
new Claim("role", roleName),
6576
new Claim("elfh_userName", user.UserName),
77+
new Claim("preferred_username", moodleUser.ToString()),
6678
};
6779

6880
if (context.Subject.HasClaim("openAthensUser", "true"))

Auth/LearningHub.Nhs.Auth/appsettings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
"3584C984-028C-4002-AA4B-58AF665AEBDD": "",
5252
"LearningHubOAClient": ""
5353
},
54+
"MoodleAPIConfig": {
55+
"BaseUrl": "",
56+
"MoodleWSRestFormat": "json",
57+
"WSToken": ""
58+
},
5459
"OaScopes": [ "" ],
5560
"AuthKey": "",
5661
"AuthOrigin": "",

0 commit comments

Comments
 (0)