|
|
@@ -49,7 +49,7 @@ namespace Teknik.Areas.Users.Controllers |
|
|
|
private readonly IHttpContextAccessor _httpContextAccessor; |
|
|
|
private ISession _session => _httpContextAccessor.HttpContext.Session; |
|
|
|
|
|
|
|
public LogoutSessionManager _logoutSessions { get; } |
|
|
|
private readonly LogoutSessionManager _logoutSessions; |
|
|
|
|
|
|
|
public UserController(ILogger<Logger> logger, Config config, TeknikEntities dbContext, LogoutSessionManager logoutSessions, IHttpContextAccessor httpContextAccessor) : base(logger, config, dbContext) |
|
|
|
{ |
|
|
@@ -83,87 +83,14 @@ namespace Teknik.Areas.Users.Controllers |
|
|
|
[HttpGet] |
|
|
|
public async Task Logout() |
|
|
|
{ |
|
|
|
// these are the sub & sid to signout |
|
|
|
//var sub = User.FindFirst("sub")?.Value; |
|
|
|
//var sid = User.FindFirst("sid")?.Value; |
|
|
|
|
|
|
|
await HttpContext.SignOutAsync("Cookies"); |
|
|
|
await HttpContext.SignOutAsync("oidc"); |
|
|
|
} |
|
|
|
|
|
|
|
[HttpPost] |
|
|
|
[AllowAnonymous] |
|
|
|
public async Task<IActionResult> Logout(string logout_token) |
|
|
|
{ |
|
|
|
Response.Headers.Add("Cache-Control", "no-cache, no-store"); |
|
|
|
Response.Headers.Add("Pragma", "no-cache"); |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
var user = await ValidateLogoutToken(logout_token); |
|
|
|
|
|
|
|
// these are the sub & sid to signout |
|
|
|
var sub = user.FindFirst("sub")?.Value; |
|
|
|
var sid = user.FindFirst("sid")?.Value; |
|
|
|
|
|
|
|
_logoutSessions.Add(sub, sid); |
|
|
|
|
|
|
|
return Ok(); |
|
|
|
} |
|
|
|
catch { } |
|
|
|
|
|
|
|
return BadRequest(); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<ClaimsPrincipal> ValidateLogoutToken(string logoutToken) |
|
|
|
{ |
|
|
|
var claims = await ValidateJwt(logoutToken); |
|
|
|
|
|
|
|
if (claims.FindFirst("sub") == null && claims.FindFirst("sid") == null) throw new Exception("Invalid logout token"); |
|
|
|
|
|
|
|
var nonce = claims.FindFirstValue("nonce"); |
|
|
|
if (!String.IsNullOrWhiteSpace(nonce)) throw new Exception("Invalid logout token"); |
|
|
|
|
|
|
|
var eventsJson = claims.FindFirst("events")?.Value; |
|
|
|
if (String.IsNullOrWhiteSpace(eventsJson)) throw new Exception("Invalid logout token"); |
|
|
|
|
|
|
|
var events = JObject.Parse(eventsJson); |
|
|
|
var logoutEvent = events.TryGetValue("http://schemas.openid.net/event/backchannel-logout"); |
|
|
|
if (logoutEvent == null) throw new Exception("Invalid logout token"); |
|
|
|
|
|
|
|
return claims; |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<ClaimsPrincipal> ValidateJwt(string jwt) |
|
|
|
{ |
|
|
|
// read discovery document to find issuer and key material |
|
|
|
var disco = await DiscoveryClient.GetAsync(_config.UserConfig.IdentityServerConfig.Authority); |
|
|
|
|
|
|
|
var keys = new List<SecurityKey>(); |
|
|
|
foreach (var webKey in disco.KeySet.Keys) |
|
|
|
{ |
|
|
|
var e = Base64Url.Decode(webKey.E); |
|
|
|
var n = Base64Url.Decode(webKey.N); |
|
|
|
|
|
|
|
var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n }) |
|
|
|
{ |
|
|
|
KeyId = webKey.Kid |
|
|
|
}; |
|
|
|
|
|
|
|
keys.Add(key); |
|
|
|
} |
|
|
|
|
|
|
|
var parameters = new TokenValidationParameters |
|
|
|
{ |
|
|
|
ValidIssuer = disco.Issuer, |
|
|
|
ValidAudience = _config.UserConfig.IdentityServerConfig.ClientId, |
|
|
|
IssuerSigningKeys = keys, |
|
|
|
|
|
|
|
NameClaimType = JwtClaimTypes.Name, |
|
|
|
RoleClaimType = JwtClaimTypes.Role |
|
|
|
}; |
|
|
|
|
|
|
|
var handler = new JwtSecurityTokenHandler(); |
|
|
|
handler.InboundClaimTypeMap.Clear(); |
|
|
|
|
|
|
|
var user = handler.ValidateToken(jwt, parameters, out var _); |
|
|
|
return user; |
|
|
|
//_logoutSessions.Add(sub, sid); |
|
|
|
} |
|
|
|
|
|
|
|
[AllowAnonymous] |