Le package de nuget ADAL .Net Core ne prend pas en charge UserPasswordCredential

Dans ADAL.Net 3.x, UserPasswordCredential est introduit par-dessus UserCredential à partir de 2.x. Mais le même UserPasswordCredential n’est pas exposé dans le .Net Core sous le même paquet de nuget?

La classe UserCredential a une seule propriété UserName

namespace Microsoft.IdentityModel.Clients.ActiveDirectory { // // Summary: // Credential used for integrated authentication on domain-joined machines. public class UserCredential { // // Summary: // Constructor to create user credential. Using this constructor would imply integrated // authentication with logged in user and it can only be used in domain joined scenarios. public UserCredential(); // // Summary: // Constructor to create credential with client id and secret // // Parameters: // userName: // Identifier of the user application requests token on behalf. public UserCredential(ssortingng userName); // // Summary: // Gets identifier of the user. public ssortingng UserName { get; } } } 

Etant donné que UserPasswordCredential n’est pas disponible dans .NetCore et que UserCredential n’utilise qu’un nom d’utilisateur de paramètre, comment saisir le mot de passe de l’utilisateur et implémenter le code ci-dessous dans .Net Core?

 authContext.AcquireTokenAsync(WebAPIResourceId, ClientId, userPasswordCredential); 

J’utilise la version ADAL 3.13.4 spécifiquement dans la version .Net Core 1.0

Pour utiliser le stream d’octroi des informations d’identification du mot de passe du propriétaire de la ressource afin d’obtenir le jeton d’access pour Azure AD, nous pouvons appeler la requête http directement à l’aide de HttpClient. Voici un exemple pour votre référence:

 HttpClient client = new HttpClient(); ssortingng tokenEndpoint = "https://login.microsoftonline.com/{tenantId}/oauth2/token"; var body = "resource={resourceUrl}&client_id={clientId}&grant_type=password&username={userName}&password={password}"; var ssortingngContent = new SsortingngContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); var result=await client.PostAsync(tokenEndpoint, ssortingngContent).ContinueWith((response) => { return response.Result.Content.ReadAsSsortingngAsync().Result; }); JObject jobject = JObject.Parse(result); var token = jobject["access_token"].Value(); 

Vous avez raison, UserPasswordCredential n’est pas disponible pour .NET Core et UserCredential n’accepte plus le nom d’utilisateur et le mot de passe. Cela signifie qu’ADAL v3 ne prend pas en charge le stream nom d’utilisateur / mot de passe sur .NET Core.

Voici ce que je fais pour contourner ce problème. J’ai reproduit le même comportement dans une méthode statique à utiliser dans .NET Core, car la classe UserPasswordCredential est manquante. Ceci est basé sur les traces de fiddler de ce qui se passe lorsque la classe UserPasswordCredential est utilisée dans la version .NET. Étant donné que la DLL .NET semble être obscurcie, il s’agit d’une meilleure tentative pour capturer ce qu’elle fait.

 public const ssortingng Saml11Bearer = "urn:ietf:params:oauth:grant-type:saml1_1-bearer"; public const ssortingng Saml20Bearer = "urn:ietf:params:oauth:grant-type:saml2-bearer"; public const ssortingng JwtBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer"; ///  /// Acquire an AAD authentication token silently for an AAD App (Native) with an AAD account /// /// NOTE: This process was ported from the Microsoft.IdentityModel.Clients.ActiveDirectory's /// AuthenticationContext.AcquireTokenAsync method, which can silently authenticate using the UserPasswordCredential class. /// Since this class is missing from .NET Core, this method can be used to perform the same without any dependencies. ///  /// AAD login /// AAD pass /// Tenant ID /// Resource ID: the Azure app that will be accessed /// The Application ID of the calling app. This guid can be obtained from Azure Portal > app auth setup > Advanced Settings public static ssortingng GetAuthTokenForAADNativeApp(ssortingng user, SecureSsortingng pass, ssortingng tenantId, ssortingng resourceUrl, ssortingng clientId) { ssortingng tokenForUser = ssortingng.Empty; ssortingng authority = "https://login.microsoftonline.com/" + tenantId; // The AD Authority used for login ssortingng clientRequestID = Guid.NewGuid().ToSsortingng(); // Discover the preferred openid / oauth2 endpoint for the tenant (by authority) ssortingng api = "https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=" + authority + "/oauth2/authorize"; ssortingng openIdPreferredNetwork = ssortingng.Empty; var client = new HttpClient(); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add("client-request-id", clientRequestID); client.DefaultRequestHeaders.Add("return-client-request-id", "true"); client.DefaultRequestHeaders.Add("Accept", "application/json"); var responseTask = client.GetAsync(api); responseTask.Wait(); if (responseTask.Result.Content != null) { var responseSsortingng = responseTask.Result.Content.ReadAsSsortingngAsync(); responseSsortingng.Wait(); try { dynamic json = JObject.Parse(responseSsortingng.Result); openIdPreferredNetwork = json.metadata[0].preferred_network; // eg login.microsoftonline.com } catch { } } if (ssortingng.IsNullOrEmpty(openIdPreferredNetwork)) openIdPreferredNetwork = "login.microsoftonline.com"; // Get the federation metadata url & federation active auth url by user realm (by user domain) responseTask = client.GetAsync("https://" + openIdPreferredNetwork + "/common/userrealm/" + user + "?api-version=1.0"); responseTask.Wait(); ssortingng federation_metadata_url = ssortingng.Empty; ssortingng federation_active_auth_url = ssortingng.Empty; if (responseTask.Result.Content != null) { var responseSsortingng = responseTask.Result.Content.ReadAsSsortingngAsync(); responseSsortingng.Wait(); try { dynamic json = JObject.Parse(responseSsortingng.Result); federation_metadata_url = json.federation_metadata_url; // eg https://sts.{domain}.com.au/adfs/services/trust/mex federation_active_auth_url = json.federation_active_auth_url; // eg https://sts.{domain}.com.au/adfs/services/trust/2005/usernamemixed } catch { } } if(ssortingng.IsNullOrEmpty(federation_metadata_url) || ssortingng.IsNullOrEmpty(federation_active_auth_url)) return ssortingng.Empty; // Get federation metadata responseTask = client.GetAsync(federation_metadata_url); responseTask.Wait(); ssortingng federationMetadataXml = null; if (responseTask.Result.Content != null) { var responseSsortingng = responseTask.Result.Content.ReadAsSsortingngAsync(); responseSsortingng.Wait(); try { federationMetadataXml = responseSsortingng.Result; } catch { } } if (ssortingng.IsNullOrEmpty(federationMetadataXml)) return ssortingng.Empty; // Post credential to the federation active auth URL ssortingng messageId = Guid.NewGuid().ToSsortingng("D").ToLower(); ssortingng postData = @"   http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue urn:uuid:" + messageId + @"  http://www.w3.org/2005/08/addressing/anonymous  " + federation_active_auth_url + @"   " + DateTime.Now.ToSsortingng("o") + @" " + DateTime.Now.AddMinutes(10).ToSsortingng("o") + @"   " + user + @" " + FromSecureSsortingng(pass) + @"        urn:federation:MicrosoftOnline   http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey http://schemas.xmlsoap.org/ws/2005/02/trust/Issue   "; var content = new SsortingngContent(postData, Encoding.UTF8, "application/soap+xml"); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add("SOAPAction", "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue"); client.DefaultRequestHeaders.Add("client-request-id", clientRequestID); client.DefaultRequestHeaders.Add("return-client-request-id", "true"); client.DefaultRequestHeaders.Add("Accept", "application/json"); responseTask = client.PostAsync(federation_active_auth_url, content); responseTask.Wait(); XmlDocument xml = new XmlDocument(); ssortingng assertion = ssortingng.Empty; ssortingng grant_type = ssortingng.Empty; if (responseTask.Result.Content != null) { HttpResponseMessage rseponse = responseTask.Result; Task responseContentTask = rseponse.Content.ReadAsSsortingngAsync(); responseContentTask.Wait(); try { xml.LoadXml(responseContentTask.Result); } catch { } var nodeList = xml.GetElementsByTagName("saml:Assertion"); if (nodeList.Count > 0) { assertion = nodeList[0].OuterXml; // The grant type depends on the assertion value returned previously  grant_type = Saml11Bearer; ssortingng majorVersion = nodeList[0].Atsortingbutes["MajorVersion"] != null ? nodeList[0].Atsortingbutes["MajorVersion"].Value : ssortingng.Empty; if (majorVersion == "1") grant_type = Saml11Bearer; if (majorVersion == "2") grant_type = Saml20Bearer; else grant_type = Saml11Bearer; // Default to Saml11Bearer } } // Post to obtain an oauth2 token to for the resource // (*) Pass in the assertion XML node encoded to base64 in the post, as is done here https://blogs.msdn.microsoft.com/azureedev/2018/01/22/accessing-the-power-bi-apis-in-a-federated-azuree-ad-setup/ UserAssertion ua = new UserAssertion(assertion, grant_type, Uri.EscapeDataSsortingng(user)); UTF8Encoding encoding = new UTF8Encoding(); Byte[] byteSource = encoding.GetBytes(ua.Assertion); ssortingng base64ua = Uri.EscapeDataSsortingng(Convert.ToBase64Ssortingng(byteSource)); postData = "resource={resourceUrl}&client_id={clientId}&grant_type={grantType}&assertion={assertion}&scope=openid" .Replace("{resourceUrl}", Uri.EscapeDataSsortingng(resourceUrl)) .Replace("{clientId}", Uri.EscapeDataSsortingng(clientId)) .Replace("{grantType}", Uri.EscapeDataSsortingng(grant_type)) .Replace("{assertion}", base64ua); content = new SsortingngContent(postData, Encoding.UTF8, "application/x-www-form-urlencoded"); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add("client-request-id", clientRequestID); client.DefaultRequestHeaders.Add("return-client-request-id", "true"); client.DefaultRequestHeaders.Add("Accept", "application/json"); responseTask = client.PostAsync("https://" + openIdPreferredNetwork + "/common/oauth2/token", content); responseTask.Wait(); if (responseTask.Result.Content != null) { var responseSsortingng = responseTask.Result.Content.ReadAsSsortingngAsync(); responseSsortingng.Wait(); try { dynamic json = JObject.Parse(responseSsortingng.Result); tokenForUser = json.access_token; } catch { } } if (ssortingng.IsNullOrEmpty(federationMetadataXml)) return ssortingng.Empty; return tokenForUser; } private static ssortingng FromSecureSsortingng(SecureSsortingng value) { ssortingng ssortingngBSTR; IntPtr bSTR = Marshal.SecureSsortingngToBSTR(value); if (bSTR == IntPtr.Zero) { return ssortingng.Empty; } try { ssortingngBSTR = Marshal.PtrToSsortingngBSTR(bSTR); } finally { Marshal.FreeBSTR(bSTR); } return ssortingngBSTR; }