Add userinfo to retrieve email claim if not provided in id_token
This commit is contained in:
@@ -130,7 +130,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Content = new FormUrlEncodedContent(httpParams)
|
Content = new FormUrlEncodedContent(httpParams)
|
||||||
};
|
};
|
||||||
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
||||||
var userJwt = JsonSerializer.Deserialize<OpenIDResult>(tokenResult)?.id_token ?? string.Empty;
|
var decodedToken = JsonSerializer.Deserialize<OpenIDResult>(tokenResult);
|
||||||
|
var userJwt = decodedToken?.id_token ?? string.Empty;
|
||||||
|
var userAccessToken = decodedToken?.access_token ?? string.Empty;
|
||||||
if (!string.IsNullOrWhiteSpace(userJwt))
|
if (!string.IsNullOrWhiteSpace(userJwt))
|
||||||
{
|
{
|
||||||
//validate JWT token
|
//validate JWT token
|
||||||
@@ -140,7 +142,23 @@ namespace CarCareTracker.Controllers
|
|||||||
if (parsedToken.Claims.Any(x => x.Type == "email"))
|
if (parsedToken.Claims.Any(x => x.Type == "email"))
|
||||||
{
|
{
|
||||||
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
||||||
} else
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(openIdConfig.UserInfoURL) && !string.IsNullOrWhiteSpace(userAccessToken))
|
||||||
|
{
|
||||||
|
//retrieve claims from userinfo endpoint if no email claims are returned within id_token
|
||||||
|
var userInfoHttpRequest = new HttpRequestMessage(HttpMethod.Get, openIdConfig.UserInfoURL);
|
||||||
|
userInfoHttpRequest.Headers.Add("Authorization", $"Bearer {userAccessToken}");
|
||||||
|
var userInfoResult = await httpClient.SendAsync(userInfoHttpRequest).Result.Content.ReadAsStringAsync();
|
||||||
|
var userInfo = JsonSerializer.Deserialize<OpenIDUserInfo>(userInfoResult);
|
||||||
|
if (!string.IsNullOrWhiteSpace(userInfo?.email ?? string.Empty))
|
||||||
|
{
|
||||||
|
userEmailAddress = userInfo?.email ?? string.Empty;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_logger.LogError($"OpenID Provider did not provide an email claim via UserInfo endpoint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
||||||
_logger.LogError($"OpenID Provider did not provide an email claim, claims returned: {string.Join(",", returnedClaims)}");
|
_logger.LogError($"OpenID Provider did not provide an email claim, claims returned: {string.Join(",", returnedClaims)}");
|
||||||
@@ -239,7 +257,9 @@ namespace CarCareTracker.Controllers
|
|||||||
Content = new FormUrlEncodedContent(httpParams)
|
Content = new FormUrlEncodedContent(httpParams)
|
||||||
};
|
};
|
||||||
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
var tokenResult = await httpClient.SendAsync(httpRequest).Result.Content.ReadAsStringAsync();
|
||||||
var userJwt = JsonSerializer.Deserialize<OpenIDResult>(tokenResult)?.id_token ?? string.Empty;
|
var decodedToken = JsonSerializer.Deserialize<OpenIDResult>(tokenResult);
|
||||||
|
var userJwt = decodedToken?.id_token ?? string.Empty;
|
||||||
|
var userAccessToken = decodedToken?.access_token ?? string.Empty;
|
||||||
if (!string.IsNullOrWhiteSpace(userJwt))
|
if (!string.IsNullOrWhiteSpace(userJwt))
|
||||||
{
|
{
|
||||||
results.Add(OperationResponse.Succeed($"Passed JWT Parsing - id_token: {userJwt}"));
|
results.Add(OperationResponse.Succeed($"Passed JWT Parsing - id_token: {userJwt}"));
|
||||||
@@ -252,6 +272,22 @@ namespace CarCareTracker.Controllers
|
|||||||
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
userEmailAddress = parsedToken.Claims.First(x => x.Type == "email").Value;
|
||||||
results.Add(OperationResponse.Succeed($"Passed Claim Validation - email"));
|
results.Add(OperationResponse.Succeed($"Passed Claim Validation - email"));
|
||||||
}
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(openIdConfig.UserInfoURL) && !string.IsNullOrWhiteSpace(userAccessToken))
|
||||||
|
{
|
||||||
|
//retrieve claims from userinfo endpoint if no email claims are returned within id_token
|
||||||
|
var userInfoHttpRequest = new HttpRequestMessage(HttpMethod.Get, openIdConfig.UserInfoURL);
|
||||||
|
userInfoHttpRequest.Headers.Add("Authorization", $"Bearer {userAccessToken}");
|
||||||
|
var userInfoResult = await httpClient.SendAsync(userInfoHttpRequest).Result.Content.ReadAsStringAsync();
|
||||||
|
var userInfo = JsonSerializer.Deserialize<OpenIDUserInfo>(userInfoResult);
|
||||||
|
if (!string.IsNullOrWhiteSpace(userInfo?.email ?? string.Empty))
|
||||||
|
{
|
||||||
|
userEmailAddress = userInfo?.email ?? string.Empty;
|
||||||
|
results.Add(OperationResponse.Succeed($"Passed Claim Validation - Retrieved email via UserInfo endpoint"));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
results.Add(OperationResponse.Failed($"Failed Claim Validation - Unable to retrieve email via UserInfo endpoint: {openIdConfig.UserInfoURL} using access_token: {userAccessToken} - Received {userInfoResult}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
var returnedClaims = parsedToken.Claims.Select(x => x.Type);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace CarCareTracker.Helper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StaticHelper
|
public static class StaticHelper
|
||||||
{
|
{
|
||||||
public const string VersionNumber = "1.4.6";
|
public const string VersionNumber = "1.4.7";
|
||||||
public const string DbName = "data/cartracker.db";
|
public const string DbName = "data/cartracker.db";
|
||||||
public const string UserConfigPath = "data/config/userConfig.json";
|
public const string UserConfigPath = "data/config/userConfig.json";
|
||||||
public const string LegacyUserConfigPath = "config/userConfig.json";
|
public const string LegacyUserConfigPath = "config/userConfig.json";
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
public bool DisableRegularLogin { get; set; } = false;
|
public bool DisableRegularLogin { get; set; } = false;
|
||||||
public bool UsePKCE { get; set; } = false;
|
public bool UsePKCE { get; set; } = false;
|
||||||
public string LogOutURL { get; set; } = "";
|
public string LogOutURL { get; set; } = "";
|
||||||
|
public string UserInfoURL { get; set; } = "";
|
||||||
public string RemoteAuthURL { get {
|
public string RemoteAuthURL { get {
|
||||||
var redirectUrl = $"{AuthURL}?client_id={ClientId}&response_type=code&redirect_uri={RedirectURL}&scope={Scope}&state={State}";
|
var redirectUrl = $"{AuthURL}?client_id={ClientId}&response_type=code&redirect_uri={RedirectURL}&scope={Scope}&state={State}";
|
||||||
if (UsePKCE)
|
if (UsePKCE)
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
public class OpenIDResult
|
public class OpenIDResult
|
||||||
{
|
{
|
||||||
public string id_token { get; set; }
|
public string id_token { get; set; }
|
||||||
|
public string access_token { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
Models/OIDC/OpenIDUserInfo.cs
Normal file
7
Models/OIDC/OpenIDUserInfo.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace CarCareTracker.Models
|
||||||
|
{
|
||||||
|
public class OpenIDUserInfo
|
||||||
|
{
|
||||||
|
public string email { get; set; } = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -165,6 +165,14 @@
|
|||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<input type="text" readonly id="inputOIDCToken" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.OIDCConfig.TokenURL">
|
<input type="text" readonly id="inputOIDCToken" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.OIDCConfig.TokenURL">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2">
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<label for="inputOIDCUserInfo">@translator.Translate(userLanguage, "OIDC UserInfo URL")</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<input type="text" readonly id="inputOIDCUserInfo" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.OIDCConfig.UserInfoURL">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user