using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Abp.Authorization; using Abp.Authorization.Users; using Abp.MultiTenancy; using Abp.Runtime.Security; using Abp.UI; using BCS.BMC.Authentication.External; using BCS.BMC.Authentication.JwtBearer; using BCS.BMC.Authorization; using BCS.BMC.Authorization.Users; using BCS.BMC.Models.TokenAuth; using BCS.BMC.MultiTenancy; using BCS.BMC.CompanyMasters.Dto; using System.Net; using System.Net.Http; using Newtonsoft.Json; using System.Net.Http.Headers; using BCS.BMC.BMC.CompanyMasters; using Abp.Domain.Repositories; using System.Runtime.Intrinsics.X86; using System.Text; using System.IO; using Abp.AutoMapper; using Abp.Domain.Entities; using BCS.BMC.BMC.FirebaseCloudMessages; namespace BCS.BMC.Controllers { [Route("api/[controller]/[action]")] public class TokenAuthController : BMCControllerBase { private readonly LogInManager _logInManager; private readonly ITenantCache _tenantCache; private readonly AbpLoginResultTypeHelper _abpLoginResultTypeHelper; private readonly TokenAuthConfiguration _configuration; private readonly IExternalAuthConfiguration _externalAuthConfiguration; private readonly IExternalAuthManager _externalAuthManager; private readonly UserRegistrationManager _userRegistrationManager; private readonly IRepository _companyMaster; private readonly IRepository _firebaseToken; ResponseMessageModel responsemessage = new ResponseMessageModel(); public TokenAuthController( LogInManager logInManager, ITenantCache tenantCache, AbpLoginResultTypeHelper abpLoginResultTypeHelper, TokenAuthConfiguration configuration, IExternalAuthConfiguration externalAuthConfiguration, IExternalAuthManager externalAuthManager, UserRegistrationManager userRegistrationManager, IRepository companyMaster, IRepository firebaseToken) { _logInManager = logInManager; _tenantCache = tenantCache; _abpLoginResultTypeHelper = abpLoginResultTypeHelper; _configuration = configuration; _externalAuthConfiguration = externalAuthConfiguration; _externalAuthManager = externalAuthManager; _userRegistrationManager = userRegistrationManager; _companyMaster = companyMaster; _firebaseToken = firebaseToken; } [HttpPost] public async Task Authenticate([FromBody] AuthenticateModel model) { var loginResult = await GetLoginResultAsync( model.UserNameOrEmailAddress, model.Password, GetTenancyNameOrNull() ); var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity)); return new AuthenticateResultModel { AccessToken = accessToken, EncryptedAccessToken = GetEncryptedAccessToken(accessToken), ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds, UserId = loginResult.User.Id }; } [HttpGet] public List GetExternalAuthenticationProviders() { return ObjectMapper.Map>(_externalAuthConfiguration.Providers); } [HttpPost] public async Task ExternalAuthenticate([FromBody] ExternalAuthenticateModel model) { var externalUser = await GetExternalUserInfo(model); var loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull()); switch (loginResult.Result) { case AbpLoginResultType.Success: { var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity)); return new ExternalAuthenticateResultModel { AccessToken = accessToken, EncryptedAccessToken = GetEncryptedAccessToken(accessToken), ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds }; } case AbpLoginResultType.UnknownExternalLogin: { var newUser = await RegisterExternalUserAsync(externalUser); if (!newUser.IsActive) { return new ExternalAuthenticateResultModel { WaitingForActivation = true }; } // Try to login again with newly registered user! loginResult = await _logInManager.LoginAsync(new UserLoginInfo(model.AuthProvider, model.ProviderKey, model.AuthProvider), GetTenancyNameOrNull()); if (loginResult.Result != AbpLoginResultType.Success) { throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt( loginResult.Result, model.ProviderKey, GetTenancyNameOrNull() ); } var accessToken = CreateAccessToken(CreateJwtClaims(loginResult.Identity)); return new ExternalAuthenticateResultModel { AccessToken = accessToken, EncryptedAccessToken = GetEncryptedAccessToken(accessToken), ExpireInSeconds = (int)_configuration.Expiration.TotalSeconds }; } default: { throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt( loginResult.Result, model.ProviderKey, GetTenancyNameOrNull() ); } } } private async Task RegisterExternalUserAsync(ExternalAuthUserInfo externalUser) { var user = await _userRegistrationManager.RegisterAsync( externalUser.Name, externalUser.Surname, externalUser.EmailAddress, externalUser.EmailAddress, Authorization.Users.User.CreateRandomPassword(), true ); user.Logins = new List { new UserLogin { LoginProvider = externalUser.Provider, ProviderKey = externalUser.ProviderKey, TenantId = user.TenantId } }; await CurrentUnitOfWork.SaveChangesAsync(); return user; } private async Task GetExternalUserInfo(ExternalAuthenticateModel model) { var userInfo = await _externalAuthManager.GetUserInfo(model.AuthProvider, model.ProviderAccessCode); if (userInfo.ProviderKey != model.ProviderKey) { throw new UserFriendlyException(L("CouldNotValidateExternalUser")); } return userInfo; } private string GetTenancyNameOrNull() { if (!AbpSession.TenantId.HasValue) { return null; } return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName; } private async Task> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName) { var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName); switch (loginResult.Result) { case AbpLoginResultType.Success: return loginResult; default: throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName); } } private string CreateAccessToken(IEnumerable claims, TimeSpan? expiration = null) { var now = DateTime.UtcNow; var jwtSecurityToken = new JwtSecurityToken( issuer: _configuration.Issuer, audience: _configuration.Audience, claims: claims, notBefore: now, expires: now.Add(expiration ?? _configuration.Expiration), signingCredentials: _configuration.SigningCredentials ); return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); } private static List CreateJwtClaims(ClaimsIdentity identity) { var claims = identity.Claims.ToList(); var nameIdClaim = claims.First(c => c.Type == ClaimTypes.NameIdentifier); // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims. claims.AddRange(new[] { new Claim(JwtRegisteredClaimNames.Sub, nameIdClaim.Value), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64) }); return claims; } private string GetEncryptedAccessToken(string accessToken) { return SimpleStringCipher.Instance.Encrypt(accessToken); } [HttpPost] public async Task ValidateTenancy([FromBody] GetUrlDto input) { Uri uri = new Uri(input.InputUrl, UriKind.Absolute); var domain = uri.Host; if (string.IsNullOrWhiteSpace(input.InputUrl)) { return BadRequest("Please Enter A Valid Url"); } var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain); if (company == null) { return BadRequest("Url Not Found"); } var result = new { CompanyId = company.Id, }; return Ok(result); } [HttpPost] public async Task Login([FromBody] LoginInputModel input) { var subDomainName = ""; var protocol = ""; if (string.IsNullOrWhiteSpace(input.CompanyUrl)) { return BadRequest("Please Enter A Valid Url"); } using (HttpClient client = new HttpClient()) { Uri uri = new Uri(input.CompanyUrl); var host = uri.Host; protocol = uri.Scheme; if (host.Split('.').Length > 2) { int lastIndex = host.LastIndexOf("."); int index = host.LastIndexOf(".", lastIndex - 1); var subdomain = host.Substring(0, index); if (subdomain != "www") { subDomainName = subdomain; } } var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == host); if (company == null) { return BadRequest("Invalid Company Url"); } // var baseUrl = uri + "api/BmcLogin"; var baseUrl = protocol + "://" + host + "/api/BmcLogin"; var data = new { usernameOrEmailAddress = input.UsernameOrEmailAddress, password = input.Password }; var requestJson = JsonConvert.SerializeObject(data); var requestContent = new StringContent(requestJson.ToString()); requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json"); HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent); if (response.IsSuccessStatusCode) { var responseStream = await response.Content.ReadAsStringAsync(); LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject(responseStream); var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == int.Parse(result.result.userId)).FirstOrDefault(); if (getTokenDetails is null) { FirebaseToken entity = new FirebaseToken(); entity.UserId = int.Parse(result.result.userId); entity.HostName = host; entity.FcmToken = input.FcmToken; await _firebaseToken.InsertAndGetIdAsync(entity); } if (getTokenDetails != null) { getTokenDetails.FcmToken = input.FcmToken; await _firebaseToken.UpdateAsync(getTokenDetails); } return Ok(result); } else if (response.StatusCode == HttpStatusCode.InternalServerError) { var contents = await response.Content.ReadAsStringAsync(); ResponseMessageModel result = JsonConvert.DeserializeObject(contents); return BadRequest(result.error.message == "Login Failed" ? "Invalid Username Or Password" : result.error.message); } return Ok(); } } [HttpPost] public async Task Registration([FromBody] RegistrationInput input) { Uri uri = new Uri(input.CompanyUrl, UriKind.Absolute); var domain = uri.Host; if (string.IsNullOrWhiteSpace(input.CompanyUrl)) { return BadRequest("Please Enter A Valid Url"); } var company = await _companyMaster.FirstOrDefaultAsync(x => x.DomainName == domain); if (company == null) { return BadRequest("Url Not Found"); } using (HttpClient client = new HttpClient()) { var baseUrl = input.CompanyUrl + "/api/services/bwac/employeeRegister/RegisterEmployeeAsNewUser"; var data = new { phoneNo = input.Phoneno, userName = input.UserNameOrEmail, password = input.Password }; var requestJson = JsonConvert.SerializeObject(data); var requestContent = new StringContent(requestJson.ToString()); requestContent.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json"); HttpResponseMessage response = await client.PostAsync(baseUrl, requestContent); if (response.IsSuccessStatusCode) { var responseStream = await response.Content.ReadAsStringAsync(); LoginOrRegisterResponseMessageModel result = JsonConvert.DeserializeObject(responseStream); return Ok(result); } else if (response.StatusCode == HttpStatusCode.InternalServerError) { var contents = await response.Content.ReadAsStringAsync(); ResponseMessageModel result = JsonConvert.DeserializeObject(contents); return BadRequest(result); } } return BadRequest(); } [HttpPost] public async Task DeleteRegisteredFcmToken([FromBody] FcmTokenDeleteInput input) { Uri uri = new Uri(input.HostName); var host = uri.Host; var getTokenDetails = _firebaseToken.GetAllList().Where(x => x.HostName == host && x.UserId == input.UserId).FirstOrDefault(); if (getTokenDetails != null) { FirebaseToken entity = new FirebaseToken(); getTokenDetails.FcmToken = null; await _firebaseToken.UpdateAsync(getTokenDetails); } else { return BadRequest("logout failed"); } return Ok("Success"); } } }