using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Claims; using System.Threading.Tasks; using Asp.Versioning; using AutoMapper; using gehGassi.Core.Interfaces; using gehGassi.Domain.Users; using gehGassi.Dto; using gehGassi.Web.Auth; using gehGassi.Web.Helper; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; namespace gehGassi.Web.Controllers.Api { [ApiController] [ApiVersion(1)] [Route("api/mobileauth")] [Route("api/v{v:apiVersion}/mobileauth")] public class ApiMobileAuthController : ApiBaseController { private readonly ITokenService _tokenService; private readonly UserManager _userManager; private readonly SignInManager _signInManager; private readonly IRefreshTokenService _refreshTokenService; const string callbackScheme = "gehgassiapp"; public ApiMobileAuthController(IMapper mapper, IOptions localizationOptions, IAppUserService appUserService, ITokenService tokenService, UserManager userManager, SignInManager signInManager, IRefreshTokenService refreshTokenService) : base(mapper, localizationOptions, appUserService) { _tokenService = tokenService; _userManager = userManager; _signInManager = signInManager; _refreshTokenService = refreshTokenService; } [HttpGet("{scheme}")] public async Task Get([FromRoute] string scheme) { try { var errorCode = CommunicationErrors.Undefined; var auth = await Request.HttpContext.AuthenticateAsync(scheme); if (!auth.Succeeded || auth?.Principal == null || !auth.Principal.Identities.Any(id => id.IsAuthenticated) || string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token"))) { // Not authenticated, challenge await Request.HttpContext.ChallengeAsync(scheme); } else { var email = string.Empty; var providerKey = string.Empty; var givenName = string.Empty; var surname = string.Empty; var token = string.Empty; if (auth.Principal != null && auth.Principal.Identities != null && auth.Principal.Identities.Any()) { var claims = auth.Principal.Identities.FirstOrDefault()?.Claims; if (claims != null) { var claimsList = claims.ToList(); if (claimsList.Any()) { email = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value; providerKey = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; givenName = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value; surname = claimsList?.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value; if (!string.IsNullOrWhiteSpace(email) && !string.IsNullOrWhiteSpace(providerKey)) { //Umgestellt auf Providerkey, falls der Benutzer die Email-Adresse geändert hat, wenn kein externer Login vorhanden, dann mit email var user = await _userManager.FindByLoginAsync("Google", providerKey) ?? await _userManager.FindByEmailAsync(email); if (user != null) { if (await _userManager.IsLockedOutAsync(user) == false) { if (await _userManager.IsEmailConfirmedAsync(user)) { if (!string.IsNullOrWhiteSpace(user.AppUserId)) { var appUser = await AppUserService.GetAsync(user.AppUserId); if (appUser != null) { if (appUser.Locked && appUser.LockedUntil < DateTimeOffset.UtcNow) { appUser.Locked = false; appUser.LockedUntil = null; await AppUserService.CommitAsync("System"); } if (!appUser.Locked) { var usersClaims = new List() { new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.GivenName, user.FirstName), new Claim(ClaimTypes.Surname, user.LastName), new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), new Claim(ClaimTypes.UserData, user.Photo ?? ""), new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""), }; var roles = await _userManager.GetRolesAsync(user); foreach (var role in roles) { usersClaims.Add(new Claim(ClaimTypes.Role, role)); } token = _tokenService.GenerateAccessToken(usersClaims); await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName); user.LastLoginDate = DateTimeOffset.UtcNow; await _userManager.UpdateAsync(user); var externalLogins = await _userManager.GetLoginsAsync(user); if (externalLogins?.FirstOrDefault(c => c.LoginProvider == "Google") == null) { await _userManager.AddLoginAsync(user, new UserLoginInfo("Google", providerKey, user.FullName)); } errorCode = CommunicationErrors.None; var responseValues = new Dictionary { { "error_code", errorCode.ToString() }, { "access_token", token }, { "email", email }, { "register", false.ToString() }, { "givenname", givenName }, { "surname", surname }, { "providerkey", providerKey } }; var callBackUrl = callbackScheme + "://#" + string.Join( "&", responseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1") .Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}")); Request.HttpContext.Response.Redirect(callBackUrl); return; } else errorCode = CommunicationErrors.Login_LockedOut; } else errorCode = CommunicationErrors.Login_Assignment_Missing; } else errorCode = CommunicationErrors.Login_Assignment_Missing; } else errorCode = CommunicationErrors.Login_Email_NotConfirmed; } else errorCode = CommunicationErrors.Login_LockedOut; } else { //Es gibt den Benutzer nicht. Registrierungs-Variante token = auth.Properties.GetTokenValue("access_token"); if (!string.IsNullOrEmpty(token)) { errorCode = CommunicationErrors.None; var responseValues = new Dictionary { { "error_code", errorCode.ToString() }, { "access_token", token }, { "email", email }, { "register", true.ToString() }, { "givenname", givenName }, { "surname", surname }, { "providerkey", providerKey } }; var callBackUrl = callbackScheme + "://#" + string.Join( "&", responseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1") .Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}")); Request.HttpContext.Response.Redirect(callBackUrl); return; } else errorCode = CommunicationErrors.Undefined; } } if(errorCode == CommunicationErrors.None) errorCode = CommunicationErrors.Register_Email_Exists; } if (errorCode == CommunicationErrors.None) errorCode = CommunicationErrors.Common_Model_Invalid; } if (errorCode == CommunicationErrors.None) errorCode = CommunicationErrors.Common_Exists; } var errorResponseValues = new Dictionary { { "error_code", errorCode.ToString() }, { "access_token", token }, { "email", email }, { "register", false.ToString() }, { "givenname", givenName }, { "surname", surname }, { "providerkey", providerKey } }; var errorCallBackUrl = callbackScheme + "://#" + string.Join( "&", errorResponseValues.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1") .Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}")); Request.HttpContext.Response.Redirect(errorCallBackUrl); } } catch (Exception ex) { Request.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; } } } }