123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- using System;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Security.Cryptography.X509Certificates;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.Identity.Client;
- using Microsoft.Identity.Client.Extensions.Msal;
- using Microsoft.InformationProtection;
- using Serilog;
- namespace AipGateway.AIP
- {
- public class AuthDelegateImplementation : IAuthDelegate
- {
- private readonly ILogger _log;
- public int LastErrNo { get; set; }
- public string LastErrMsg { get; set; }
- private readonly AipConfig _aipConfig;
- private readonly IConfidentialClientApplication _confidentialApp = null;
- private readonly IPublicClientApplication _publicApp = null;
- // [Obsolete("Obsolete")] private TokenCache _tokenCache = new TokenCache();
- public AuthDelegateImplementation(Serilog.Core.Logger logger, AipConfig aipConfig)
- {
- _log = logger.ForContext<AuthDelegateImplementation>();
- _aipConfig = aipConfig;
- LastErrNo = 0;
- LastErrMsg = String.Empty;
- var storageProperties =
- new StorageCreationPropertiesBuilder(
- "AIPGateway.Cache",
- Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
- .Build();
- var cacheHelper = MsalCacheHelper.CreateAsync(storageProperties).GetAwaiter().GetResult();
- if (_aipConfig.LoginType == AipAuthLoginType.authLoginPassword)
- {
- // _confidentialApp = ConfidentialClientApplicationBuilder
- // .Create(_aipConfig.ClientId)
- // .WithClientSecret(_aipConfig.SecretValue)
- // // .WithAuthority($"https://login.microsoftonline.com/{_aipConfig.TenantId}")
- // // .WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
- // .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
- // .Build();
- // var authority = $"https://login.windows.net/{_aipConfig.TenantId}";
- // BrokerOptions brokerOptions = new BrokerOptions(BrokerOptions.OperatingSystems.Windows);
- // _confidentialApp = PublicClientApplicationBuilder
- // .Create(_aipConfig.ClientId)
- // .WithAuthority(authority)
- // .WithDefaultRedirectUri()
- // .WithBroker(brokerOptions)
- // .Build();
- ConfidentialClientApplicationOptions options = new ConfidentialClientApplicationOptions()
- {
- ClientSecret = _aipConfig.SecretValue,
- ClientId = _aipConfig.ClientId,
- TenantId = _aipConfig.TenantId,
- RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient",
- Instance = "https://login.microsoftonline.com/"
- };
-
- _confidentialApp = ConfidentialClientApplicationBuilder
- .CreateWithApplicationOptions(options)
- .WithRedirectUri(options.RedirectUri)
- // .WithLegacyCacheCompatibility(false)
- // .WithExperimentalFeatures() // for PoP
- // .WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
- .Build();
- // IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(options)
- // .WithCertificate(certificate)
- // .Build();
- //Console.WriteLine(" AppTokenCache: {0}", _confidentialApp.AppTokenCache);
- //Console.WriteLine("UserTokenCache: {0}", _confidentialApp.UserTokenCache);
- cacheHelper.RegisterCache(_confidentialApp.UserTokenCache);
- }
- else if (_aipConfig.LoginType == AipAuthLoginType.authLoginCert)
- {
- var authority = $"https://login.windows.net/{_aipConfig.TenantId}";
- var myCertificate = new X509Certificate2(_aipConfig.CertThumbPrint, "hanteinfo1234!");
- X509Certificate2 certificate = new X509Certificate2(myCertificate);
- _confidentialApp = ConfidentialClientApplicationBuilder.Create(_aipConfig.ClientId)
- .WithCertificate(certificate)
- .WithAuthority(new Uri(authority))
- .Build();
- cacheHelper.RegisterCache(_confidentialApp.UserTokenCache);
- }
- else
- {
- _publicApp = PublicClientApplicationBuilder.Create(_aipConfig.ClientId)
- .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
- .WithAuthority(AzureCloudInstance.AzurePublic, _aipConfig.TenantId)
- .Build();
- cacheHelper.RegisterCache(_publicApp.UserTokenCache);
- }
- }
- public void ResetError()
- {
- LastErrNo = 0;
- LastErrMsg = string.Empty;
- }
- private void SetError(int errNo, string errMsg1, string errMsg2 = "No Exception Message.")
- {
- LastErrNo = errNo;
- LastErrMsg = errMsg1 + "\r\n" + errMsg2;
- _log.Error("AuthDelegateImplementation::SetError ==> {0}, {1}, {2}", errNo, errMsg1, errMsg2);
- }
- public string AcquireToken(Identity identity, string authority, string resource, string claim)
- {
- //Console.WriteLine("AuthDelegateImplementation::AcquireToken ==> LoginType: {0}", _aipConfig.LoginType);
- if (_aipConfig.LoginType == AipAuthLoginType.authLoginPassword)
- {
- return AcquireTokenByCertificate(identity, authority, resource, claim);
- }
-
- if (_aipConfig.LoginType == AipAuthLoginType.authLoginCert)
- {
- return AcquireTokenByCertificate(identity, authority, resource, claim);
- }
- return AcquireTokenById(identity, authority, resource, claim);
- }
- private string AcquireTokenByCertificate(Identity identity, string authority, string resource, string claims)
- {
- //ddddddddddddddddddddddddddddddddd: https://login.windows.net/common, https://syncservice.o365syncservice.com/
- //ddddddddddddddddddddddddddddddddd: https://login.windows.net/common, https://aadrm.com
- //Console.WriteLine("ddddddddddddddddddddddddddddddddd: {0}, {1}", authority, resource);
- // AuthenticationResult result;
- // var authorityUri = new Uri(authority);
- // authority = $"https://{authorityUri.Host}/{_aipConfig.TenantId}";
- var scopes = new[] { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };
- try
- {
- #if false
- IConfidentialClientApplication app;
- ConfidentialClientApplicationOptions options = new ConfidentialClientApplicationOptions()
- {
- ClientSecret = _aipConfig.SecretValue,
- ClientId = _aipConfig.ClientId,
- TenantId = _aipConfig.TenantId,
- RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient",
- Instance = "https://login.microsoftonline.com/"
- };
- app = ConfidentialClientApplicationBuilder
- .CreateWithApplicationOptions(options)
- .WithRedirectUri(options.RedirectUri)
- // .WithLegacyCacheCompatibility(false)
- // .WithExperimentalFeatures() // for PoP
- // .WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
- .Build();
- #endif
- AuthenticationResult result = null;
- //Console.WriteLine("B: AppTokenCache: {0}", _confidentialApp.AppTokenCache);
- //Console.WriteLine("B: UserTokenCache: {0}", _confidentialApp.UserTokenCache);
- #if false
- result = _confidentialApp.AcquireTokenForClient(scopes)
- .ExecuteAsync()
- .GetAwaiter()
- .GetResult();
- result = _confidentialApp.AcquireTokenForClient(scopes).ExecuteAsync().Result;
- #else
- result = _confidentialApp.AcquireTokenForClient(scopes)
- .ExecuteAsync(CancellationToken.None)
- .ConfigureAwait(false)
- .GetAwaiter()
- .GetResult();
- #endif
- //_log.Information("AcquireTokenByCertificate: {0}, {1}", identity.Email, identity.Name);
- // result = _confidentialApp.AcquireTokenForClient(scopes)
- // .WithTenantId(_aipConfig.TenantId)
- // .ExecuteAsync()
- // .GetAwaiter()
- // .GetResult();
- // result = _confidentialApp.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
- //Console.WriteLine("A: AppTokenCache: {0}", _confidentialApp.AppTokenCache);
- //Console.WriteLine("A: UserTokenCache: {0}", _confidentialApp.UserTokenCache);
- //Console.WriteLine("A: AccessToken: {0}", result.AccessToken);
- return result.AccessToken;
- }
- catch (MsalUiRequiredException ex) when (ex.Message.Contains("AADSTS70011"))
- {
- // Invalid scope. The scope has to be of the form "https://resourceurl/.default"
- // Mitigation: change the scope to be as expected
- SetError(1, "AcquireTokenByCertificate::AcquireTokenByCertificate, Scope provided is not supported.", ex.Message);
- }
- catch (Exception ex)
- {
- SetError(1, "AcquireTokenByCertificate::AcquireTokenByCertificate Failed.", ex.Message);
- }
- return null;
- }
- // private string AcquireTokenByCertificate_Temp(Identity identity, string authority, string resource, string claims)
- // {
- // AuthenticationResult result;
- // var authorityUri = new Uri(authority);
- // authority = $"https://{authorityUri.Host}/{_aipConfig.TenantId}";
- //
- // var scopes = new[] { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };
- //
- // try
- // {
- // var accounts = (_confidentialApp.GetAccountsAsync()).GetAwaiter().GetResult();
- // result = _confidentialApp.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
- // .ExecuteAsync().GetAwaiter().GetResult();
- //
- // // result = _confidentialApp.AcquireTokenForClient(scopes)
- // // .ExecuteAsync().GetAwaiter().GetResult();
- //
- // Console.WriteLine("AuthDelegateImplementation::AcquireTokenByCertificate ==> AcquireTokenSilent Succeed.");
- // return result.AccessToken;
- // }
- // catch (MsalUiRequiredException)
- // {
- // Console.WriteLine("AuthDelegateImplementation::AcquireTokenByCertificate ==> AcquireTokenSilent Failed. Login AcquireTokenForClient.");
- // try
- // {
- // result = _confidentialApp.AcquireTokenForClient(scopes)
- // .ExecuteAsync().GetAwaiter().GetResult();
- // // result = _confidentialApp.AcquireTokenForClient(scopes)
- // // .WithTenantId(_aipConfig.TenantId)
- // // .ExecuteAsync()
- // // .GetAwaiter()
- // // .GetResult();
- // // result = _confidentialApp.AcquireTokenForClient(scopes).ExecuteAsync().GetAwaiter().GetResult();
- // }
- // catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
- // {
- // // Invalid scope. The scope has to be of the form "https://resourceurl/.default"
- // // Mitigation: change the scope to be as expected
- // SetError(1, "AcquireTokenByPassword.Scope provided is not supported.", ex.Message);
- // return null;
- // }
- // }
- //
- // return result.AccessToken;
- // }
- private string AcquireTokenById(Identity identity, string authority, string resource, string claims)
- {
- //Console.WriteLine("AcquireTokenById::AcquireTokenByPassword");
- AuthenticationResult result;
- var authorityUri = new Uri(authority);
- authority = $"https://{authorityUri.Host}/{_aipConfig.TenantId}";
- // var app = PublicClientApplicationBuilder.Create(_aipConfig.ClientId)
- // .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
- // .WithAuthority(AzureCloudInstance.AzurePublic, _aipConfig.TenantId)
- // .Build();
- var accounts = (_publicApp.GetAccountsAsync()).GetAwaiter().GetResult();
- // Append .default to the resource passed in to AcquireToken().
- var scopes = new[] { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };
- try
- {
- result = _publicApp.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync().Result;
- //Console.WriteLine("AuthDelegateImplementation::AcquireTokenById ==> AcquireTokenSilent Succeed.");
- return result.AccessToken;
- }
- catch (MsalUiRequiredException)
- {
- //Console.WriteLine("AuthDelegateImplementation::AcquireTokenById ==> AcquireTokenSilent Failed. Login AcquireTokenForClient.");
- result = _publicApp.AcquireTokenInteractive(scopes)
- .WithAccount(accounts.FirstOrDefault())
- .WithPrompt(Prompt.SelectAccount)
- .ExecuteAsync()
- .ConfigureAwait(false)
- .GetAwaiter()
- .GetResult();
- }
- catch (Exception ex)
- {
- SetError(1, "AcquireTokenById.Login Failed.", ex.Message);
- return null;
- }
- return result.AccessToken;
- }
-
- public async Task<AuthenticationResult> AcquireTokenAsync(string authority, string resource, string claims)
- {
- AuthenticationResult result = null;
- if (authority.ToLower().Contains("common"))
- {
- var authorityUri = new Uri(authority);
- authority = String.Format("https://{0}/{1}", authorityUri.Host, _aipConfig.TenantId);
- }
-
- var app = PublicClientApplicationBuilder.Create(_aipConfig.ClientId)
- .WithAuthority(authority)
- .WithDefaultRedirectUri()
- .Build();
- var accounts = (app.GetAccountsAsync()).GetAwaiter().GetResult();
- // Append .default to the resource passed in to AcquireToken().
- string[] scopes = { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };
- try
- {
- result = await app.AcquireTokenSilent(new[] { "https://aadrm.com/user_impersonation" }, accounts.FirstOrDefault()).ExecuteAsync();
- // result = await _app.AcquireTokenSilent(scopes,
- // accounts.FirstOrDefault())
- // .ExecuteAsync();
- }
- catch (MsalUiRequiredException)
- {
- result = app.AcquireTokenInteractive(scopes)
- .WithAccount(accounts.FirstOrDefault())
- .WithPrompt(Prompt.SelectAccount)
- .ExecuteAsync()
- .ConfigureAwait(false)
- .GetAwaiter()
- .GetResult();
- }
- // Return the token. The token is sent to the resource.
- return result;
- }
- // public Identity GetUserIdentity()
- // {
- // try
- // {
- // string resource = "https://graph.microsoft.com/";
- //
- // AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common", tokenCache);
- // var result = authContext.AcquireTokenAsync(resource, appInfo.ApplicationId, new Uri(redirectUri), new PlatformParameters(PromptBehavior.Always)).Result;
- // return new Identity(result.UserInfo.DisplayableId);
- //
- // }
- // catch (Exception ex)
- // {
- // throw ex;
- // }
- // }
- // private async Task<string> GetAccessTokenOnBehalfOfUser(string authority, string resource)
- // {
- // IConfidentialClientApplication app;
- //
- // if (false)
- // {
- // // Read X509 cert from local store and build ClientAssertionCertificate.
- // X509Certificate2 cert = Utilities.ReadCertificateFromStore(_aipConfig.CertThumbPrint);
- //
- // // Create confidential client using certificate.
- // app = ConfidentialClientApplicationBuilder.Create(_aipConfig.ClientId)
- // .WithRedirectUri(resource)
- // .WithAuthority(authority)
- // .WithCertificate(cert)
- // .Build();
- // }
- //
- // else
- // {
- // // Create confidential client using client secret.
- // app = ConfidentialClientApplicationBuilder.Create(_aipConfig.ClientId)
- // .WithRedirectUri(resource)
- // .WithAuthority(authority)
- // .WithClientSecret(_aipConfig.SecretValue)
- // .Build();
- // }
- //
- // // Store user access token of authenticated user.
- // var ci = (ClaimsIdentity)_claimsPrincipal.Identity;
- // string userAccessToken = (string)ci.BootstrapContext;
- //
- //
- // // Generate a user assertion with the UPN and access token.
- // UserAssertion userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer");
- //
- // // Append .default to the resource passed in to AcquireToken().
- // List<string> scopes = new List<string>() { resource[resource.Length - 1].Equals('/') ? $"{resource}.default" : $"{resource}/.default" };
- //
- // AuthenticationResult result = await app.AcquireTokenOnBehalfOf(scopes, userAssertion)
- // .ExecuteAsync();
- //
- // // Return the token to the API caller
- // return (result.AccessToken);
- // }
- }
- }
|