using IdentityServer.PublishedLanguage.Dto; using IdentityServer.Wrapper.Services; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Netmash.Security.Authentication.Identity.Abstractions; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Headers; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using c = Netmash.Security.Authentication.Identity.Constants; namespace Netmash.Security.Authentication.Identity { public class IdentityAuthenticationHandler : AuthenticationHandler { private readonly IIdentityService _identityService; private readonly IAuthenticationOptions _authenticationOptions; private readonly ILogger _logger; public IdentityAuthenticationHandler(IOptionsMonitor options, ILoggerFactory loggerFactory, UrlEncoder encoder, ISystemClock clock, IIdentityService identityService, IAuthenticationOptions authenticationOptions, ILogger logger) : base(options, loggerFactory, encoder, clock) { _identityService = identityService; _authenticationOptions = authenticationOptions; _logger = logger; } protected override async Task HandleAuthenticateAsync() { var token = GetAuthorizationToken(); if (token != null) { TokenCore tokenCore; try { tokenCore = await _identityService.Authorize(token); } catch (Exception e) { _logger.LogError(e, "Identity service authorization failed"); return AuthenticateResult.Fail("Invalid authorization"); } if (tokenCore == null) return AuthenticateResult.Fail("Invalid token"); var ticket = GetAuthenticationTicket(tokenCore); return AuthenticateResult.Success(ticket); } var authenticateAsGuest = _authenticationOptions.AuthenticateAsGuest?.Invoke(Request) ?? false; if (authenticateAsGuest) { var guestTicket = GetGuestAuthenticationTicket(_authenticationOptions.GuestUserId, _authenticationOptions.GuestUserName); return AuthenticateResult.Success(guestTicket); } return AuthenticateResult.Fail("Missing authorization header"); } private string GetAuthorizationToken() { if (Request.Headers.ContainsKey("Authorization")) { var authorizationHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); var token = authorizationHeader.Parameter; return token; } if (_authenticationOptions.AcceptTokenFromQuery && Request.Query.Count > 0 && Request.Query.ContainsKey(c.QueryParams.Token)) { var token = Request.Query[c.QueryParams.Token]; return token.ToString(); } return null; } private AuthenticationTicket GetGuestAuthenticationTicket(int guestId, string guestName) { var claims = new[] { new Claim(ClaimTypes.NameIdentifier, guestId.ToString()), new Claim(ClaimTypes.Name, guestName), new Claim(Constants.ClaimTypes.IsGuestUser, bool.TrueString) }; var ticket = GetAuthenticationTicket(claims); return ticket; } private AuthenticationTicket GetAuthenticationTicket(TokenCore tokenCore) { var claimCollection = new Dictionary() { { ClaimTypes.NameIdentifier, tokenCore.UserId.ToString() }, { ClaimTypes.Name, tokenCore.UserName }, { Constants.ClaimTypes.UserName, tokenCore.UserName } }; if (tokenCore.FirstName != null) claimCollection.Add(Constants.ClaimTypes.FirstName, tokenCore.FirstName); if (tokenCore.LastName != null) claimCollection.Add(Constants.ClaimTypes.LastName, tokenCore.LastName); if (tokenCore.ProfilePictureUrl != null) claimCollection.Add(Constants.ClaimTypes.ProfilePictureUrl, tokenCore.ProfilePictureUrl); if (tokenCore.Email != null) claimCollection.Add(ClaimTypes.Email, tokenCore.Email); if (tokenCore.Claims != null && tokenCore.Claims.Any()) { foreach (var claim in tokenCore.Claims) claimCollection.Add(claim.Key, claim.Value); } var claims = claimCollection.Select(z => new Claim(z.Key, z.Value)).ToArray(); var ticket = GetAuthenticationTicket(claims); return ticket; } private AuthenticationTicket GetAuthenticationTicket(Claim[] claims) { var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return ticket; } } }