Skip to content

Commit 70fe40c

Browse files
committed
Sends JWT auth token to Tableau and redirects to dashboard if successful
1 parent 49250ce commit 70fe40c

File tree

4 files changed

+71
-32
lines changed

4 files changed

+71
-32
lines changed

DigitalLearningSolutions.Data/Extensions/ConfigurationExtensions.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ public static class ConfigurationExtensions
5454
private const string TableauClientSecret = "ClientSecret";
5555
private const string TableauUsername = "Username";
5656
private const string TableauClientName = "ClientName";
57-
57+
private const string TableauSiteUrl = "SiteUrl";
58+
private const string TableauDashboardUrl = "CompetencyDashboardUrl";
5859
public static string GetAppRootPath(this IConfiguration config)
5960
{
6061
return config[AppRootPathName]!;
@@ -185,7 +186,7 @@ public static int GetExportQueryRowLimit(this IConfiguration config)
185186
}
186187
public static int GetMaxBulkUploadRowsLimit(this IConfiguration config)
187188
{
188-
int.TryParse(config[MaxBulkUploadRowsLimitKey],out int limitKey);
189+
int.TryParse(config[MaxBulkUploadRowsLimitKey], out int limitKey);
189190
return limitKey;
190191
}
191192

@@ -206,7 +207,7 @@ public static string GetLearningHubAuthenticationClientSecret(this IConfiguratio
206207

207208
public static long GetFreshdeskCreateTicketGroupId(this IConfiguration config)
208209
{
209-
long.TryParse(config[FreshdeskCreateTicketGroupId], out long ticketGroupId);
210+
long.TryParse(config[FreshdeskCreateTicketGroupId], out long ticketGroupId);
210211
return ticketGroupId;
211212
}
212213
public static long GetFreshdeskCreateTicketProductId(this IConfiguration config)
@@ -239,5 +240,13 @@ public static string GetTableauUser(this IConfiguration config)
239240
{
240241
return config[$"{TableauSectionKey}:{TableauUsername}"]!;
241242
}
243+
public static string GetTableauSiteUrl(this IConfiguration config)
244+
{
245+
return config[$"{TableauSectionKey}:{TableauSiteUrl}"]!;
246+
}
247+
public static string GetTableauDashboardUrl(this IConfiguration config)
248+
{
249+
return config[$"{TableauSectionKey}:{TableauDashboardUrl}"]!;
250+
}
242251
}
243252
}

DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/SelfAssessmentReports/SelfAssessmentReportsController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using DigitalLearningSolutions.Data.Utilities;
1313
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.Reports;
1414
using DigitalLearningSolutions.Web.Helpers.ExternalApis;
15+
using System.Threading.Tasks;
1516

1617
[FeatureGate(FeatureFlags.RefactoredTrackingSystem)]
1718
[Authorize(Policy = CustomPolicies.UserCentreAdmin)]
@@ -69,11 +70,12 @@ public IActionResult DownloadSelfAssessmentReport(int selfAssessmentId)
6970
}
7071
[HttpGet]
7172
[Route("LaunchTableauDashboards")]
72-
public IActionResult LaunchTableauDashboards()
73+
public async Task<IActionResult> LaunchTableauDashboards()
7374
{
7475
var userEmail = User.GetUserPrimaryEmail();
7576
var jwt = tableauConnectionHelper.GetTableauJwt(userEmail);
76-
return RedirectToAction("Index");
77+
var url = await tableauConnectionHelper.AuthenticateUserAsync(jwt);
78+
return RedirectToPage(url);
7779
}
7880
}
7981
}

DigitalLearningSolutions.Web/Helpers/ExternalApis/TableauConnectionHelper.cs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,83 @@
88
using System;
99
using Microsoft.Extensions.Configuration;
1010
using DigitalLearningSolutions.Data.Extensions;
11+
using DocumentFormat.OpenXml.Bibliography;
12+
using Microsoft.FeatureManagement.FeatureFilters;
13+
using System.Net.Http.Headers;
14+
using System.Net.Http;
15+
using System.Threading.Tasks;
1116

1217
public interface ITableauConnectionHelperService
13-
{
14-
string GetTableauJwt(string email);
15-
}
18+
{
19+
string GetTableauJwt(string email);
20+
Task<string> AuthenticateUserAsync(string jwtToken);
21+
}
1622
public class TableauConnectionHelper : ITableauConnectionHelperService
1723
{
18-
private readonly string connectedAppClient;
24+
private readonly string connectedAppClientName;
1925
private readonly string connectedAppSecretKey;
2026
private readonly string connectedAppClientId;
27+
private readonly string tableauUrl;
28+
private readonly string dashboardUrl;
2129
private readonly string user;
2230
public TableauConnectionHelper(IConfiguration config)
2331
{
24-
connectedAppClient = config.GetTableauClientName();
32+
connectedAppClientName = config.GetTableauClientName();
2533
connectedAppClientId = config.GetTableauClientId();
2634
connectedAppSecretKey = config.GetTableauClientSecret();
35+
tableauUrl = config.GetTableauSiteUrl();
36+
dashboardUrl = config.GetTableauDashboardUrl();
2737
user = config.GetTableauUser();
2838
}
2939
public string GetTableauJwt(string email)
3040
{
3141
var tokenHandler = new JwtSecurityTokenHandler();
32-
var key = Encoding.ASCII.GetBytes(connectedAppSecretKey);
33-
34-
var tokenDescriptor = new SecurityTokenDescriptor
42+
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(connectedAppSecretKey));
43+
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
44+
var claims = new[]
3545
{
36-
Issuer = connectedAppClientId,
37-
Audience = "tableau",
38-
Subject = new ClaimsIdentity(new[]
39-
{
4046
new Claim(JwtRegisteredClaimNames.Sub, user),
41-
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
47+
new Claim(JwtRegisteredClaimNames.Iss, connectedAppClientId),
4248
new Claim("scp", "tableau:views:embed"),
43-
new Claim("scp", "tableau:metrics:embed"),
44-
new Claim("users.primaryemail", email)
45-
}),
46-
Expires = DateTime.UtcNow.AddMinutes(5),
47-
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
48-
Claims = new Dictionary<string, object>
49-
{
50-
{ "kid", connectedAppClientId },
51-
{ "iss", connectedAppClient }
52-
}
49+
new Claim("users.primaryemail", email),
50+
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
51+
new Claim(JwtRegisteredClaimNames.Exp,
52+
new DateTimeOffset(DateTime.UtcNow.AddMinutes(20)).ToUnixTimeSeconds().ToString())
5353
};
5454

55-
var token = tokenHandler.CreateToken(tokenDescriptor);
56-
var tokenString = tokenHandler.WriteToken(token);
55+
var token = new JwtSecurityToken(
56+
issuer: connectedAppClientId,
57+
audience: "tableau",
58+
claims: claims,
59+
expires: DateTime.UtcNow.AddMinutes(20),
60+
signingCredentials: credentials);
5761

58-
return tokenString;
62+
return new JwtSecurityTokenHandler().WriteToken(token);
5963
}
6064

65+
public async Task<string> AuthenticateUserAsync(string jwtToken)
66+
{
67+
using (var client = new HttpClient())
68+
{
69+
client.BaseAddress = new Uri(tableauUrl);
70+
client.DefaultRequestHeaders.Accept.Clear();
71+
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
72+
73+
var requestContent = new StringContent($"{{ \"token\": \"{jwtToken}\" }}", Encoding.UTF8, "application/json");
74+
75+
HttpResponseMessage response = await client.PostAsync("/api/3.8/auth/signin", requestContent); // Adjust API version as needed
76+
77+
if (response.IsSuccessStatusCode)
78+
{
79+
string responseBody = await response.Content.ReadAsStringAsync();
80+
// Process the response body if needed
81+
return dashboardUrl; // Return the response for further processing
82+
}
83+
else
84+
{
85+
throw new Exception("Failed to authenticate with Tableau Server: " + response.ReasonPhrase);
86+
}
87+
}
88+
}
6189
}
6290
}

DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/SelfAssessmentReports/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
</ul>
4444
@if (Model.SelfAssessmentSelects.Any())
4545
{
46-
<a asp-controller="SelfAssessmentReports" asp-action="LaunchTableau">@($"View Tableau Competency Dashboards")</a>
46+
<a asp-controller="SelfAssessmentReports" asp-action="LaunchTableauDashboards">@($"View Tableau Competency Dashboards")</a>
4747
}
4848

4949
</div>

0 commit comments

Comments
 (0)