Connect-AzureRmAccount : Remove Credential parameter from User login parameter set
Closed this issue · 12 comments
Description
Login-AzureRMAccount when using PowerShell Core and AzureRM.Netcore cannot accept PSCredentials.
Using interactive login via browser works fine however.
PS /> Login-AzureRmAccount -Credential $AZScred -Verbose
VERBOSE: Performing the operation "log in" on target "User account in environment 'AzureCloud'".
Login-AzureRmAccount : password_required_for_managed_user: Password is required for managed user
At line:1 char:1
+ Login-AzureRmAccount -Credential $AZScred -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Add-AzureRmAccount], AadAuthenticationFailedException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.AddAzureRMAccountCommand
Script/Steps for Reproduction
It was run from Docker: docker run -ti microsoft/powershell
Install-Module AzureRM.NetCore -Force
Import-Module AzureRM.Netcore
Import-Module AzureRM.Profile.Netcore
Add-AzureRMEnvironment -Name "AzureStackUser" -ArmEndpoint "https://management.x.x"
# Sign in to your environment
# Create your Credentials
$AZSusername = "Admin@x.onmicrosoft.com"
$AZSpassword = 'Password123'
$AZSuserPassword = ConvertTo-SecureString "$AZSpassword" -AsPlainText -Force
$AZScred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AZSusername,$AZSuserPassword
Login-AzureRmAccount -Credential $AZScred -EnvironmentName "AzureStackUser"
Module Version
PS /> get-module
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 0.10.0 AzureRM.Netcore
Script 0.10.0 AzureRM.Profile.Netcore {Add-AzureRmAccount, Add-AzureRmEnvironment, Clear-AzureR...
Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Content, Clear-Content, Clear-Item, Clear-ItemProper...
Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Cr...
Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Script 1.1.7.0 PackageManagement {Find-Package, Find-PackageProvider, Get-Package, Get-Pac...
Script 1.6.0 PowerShellGet {Find-Command, Find-DscResource, Find-Module, Find-RoleCa...
Script 1.2 PSReadLine {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-P...
Environment Data
PS /> $PSVersionTable
Name Value
---- -----
PSVersion 6.0.2
PSEdition Core
GitCommitId v6.0.2
OS Linux 4.9.60-linuxkit-aufs #1 SMP Mon Nov 6 16:00:12 UTC 2017
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
@MiYanni can you look at this issue?
@cblackuk This will be a bit before I investigate specific netcore issues. I'm nearly done getting the rest of the module projects building properly in netcore. So, I'll be doing a lot of testing in the next few weeks. I'll make sure to check this issue during that timeframe.
This is by design. Usename + Password authentication is not supported in NetCore - you must use device login or service princpal login
@markcowl If that is true, we shouldn't expose the -Credential
parameter in NetCore.
@MiYanni -Credential is used with Service Principal as well as User Principal login. We should likely remove Credential from user parameter set, but the parameter itself will remain.
@MiYanni @markcowl
As I am sure you know the issue here actually is with ActiveDirectory DLL that does not support Password in its class on .NETCore but that is only the beginning of the problem... See below:
What I mean by that is:
docker run -ti azuresdk/azure-powershell-core
### It wants to load the dll from NetCoreModule
$adal = "/usr/local/share/powershell/Modules/AzureRM.Profile.Netcore/Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
[System.Reflection.Assembly]::LoadFrom($adal)
Function GetAuthToken
{
param
(
[Parameter(Mandatory=$true)]
$TenantName
)
Import-Module Azure
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$TenantName"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$Credential = Get-Credential
$AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
return $authResult
}
If you just take this:
PS /> $AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential"
PS /> $AADCredential
UserName
--------
PS /> $AADCredential.
UserName Equals GetHashCode GetType ToString
PS /> $AADCredential.
UserName Equals GetHashCode GetType ToString
PS /> $AADCredential | gm
TypeName: Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
UserName Property string UserName {get;}
PS /> $AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList user,
password
New-Object : Cannot find an overload for "UserCredential" and the argument count: "2".
At line:1 char:20
+ ... redential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirecto ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
You can see above that it does not allow second Argument to be passed in the class/object definition.
Therefore, I did the following (thinking basically to import the same DLL that works on Desktop PowerShell to Core to see if it will work)
Save-Module -Name Microsoft.ADAL.PowerShell -Path /tmp
$adal = "/tmp/Microsoft.ADAL.PowerShell/1.12/Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
[System.Reflection.Assembly]::LoadFrom($adal)
GAC Version Location
--- ------- --------
False v4.0.30319 /tmp/Microsoft.ADAL.PowerShell/1.12/Microsoft.IdentityModel.Clients.ActiveDirectory.dll
$AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList user,password
PS /> $AADCredential
UserName
--------
user
This shows that we can now pass second Argument.
So let's try to pass it correctly:
PS /> $clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
PS /> $redirectUri = "urn:ietf:wg:oauth:2.0:oob"
PS /> $resourceAppIdURI = "https://graph.microsoft.com"
PS /> $authority = "https://login.microsoftonline.com/common"
PS /> $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
PS /> $Credential = Get-Credential
PowerShell credential request
Enter your credentials.
User: Admin@x.onmicrosoft.com
Password for user Admin@x.onmicrosoft.com: ***********
PS /> $AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
PS /> $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
Exception calling "AcquireToken" with "3" argument(s): "Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=ne
utral, PublicKeyToken=b77a5c561934e089'."
At line:1 char:5
+ $authResult = $authContext.AcquireToken($resourceAppIdURI, $clien ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TypeLoadException
For clarity Actual Error is:
PS /> $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
Exception calling "AcquireToken" with "3" argument(s): "Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=ne
utral, PublicKeyToken=b77a5c561934e089'."
At line:1 char:5
+ $authResult = $authContext.AcquireToken($resourceAppIdURI, $clien ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TypeLoadException
When you use https://www.jetbrains.com/decompiler/ to open DLLs. you can see first of all confirmation of the Arguments not being created as Desktop AD DLL has got additional overload:
// Decompiled with JetBrains decompiler
// Type: Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential
// Assembly: Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.19.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: C5333A68-57A4-4EFC-A3FA-EB33FD01628E
// Assembly location: C:\Temp\Microsoft.ADAL.PowerShell\1.12\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
using System.Security;
namespace Microsoft.IdentityModel.Clients.ActiveDirectory
{
public sealed class UserCredential
{
public UserCredential()
{
this.UserAuthType = UserAuthType.IntegratedAuth;
}
public UserCredential(string userName)
{
this.UserName = userName;
this.UserAuthType = UserAuthType.IntegratedAuth;
}
public string UserName { get; internal set; }
internal UserAuthType UserAuthType { get; private set; }
public UserCredential(string userName, string password)
{
this.UserName = userName;
this.Password = password;
this.UserAuthType = UserAuthType.UsernamePassword;
}
public UserCredential(string userName, SecureString securePassword)
{
this.UserName = userName;
this.SecurePassword = securePassword;
this.UserAuthType = UserAuthType.UsernamePassword;
}
internal string Password { get; private set; }
internal SecureString SecurePassword { get; private set; }
internal char[] PasswordToCharArray()
{
if (this.SecurePassword != null)
return this.SecurePassword.ToCharArray();
if (this.Password == null)
return (char[]) null;
return this.Password.ToCharArray();
}
}
}
Basically this:
public UserCredential(string userName, SecureString securePassword)
Sadly when this gets invoked C# is trying to load System.Core DLL. (mind you on NetCore version of that DLL the whole securePassword is not even listed at all inside that UserCredential Class)
This is caused by System.Core DLL not being able to load SHA256cng because this is trying to load SHA256
// Decompiled with JetBrains decompiler
// Type: System.Security.Cryptography.SHA256Cng
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 3B8EC409-2940-4CA6-85B7-E766485A6809
// Assembly location: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Core.dll
using System.Security.Permissions;
namespace System.Security.Cryptography
{
[HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
public sealed class SHA256Cng : SHA256
In turn SHA256 wants to use HashAlgorythm and all of those are in mscorlib.dll but in DotNet they do not work correctly as stated here:
http://support372.rssing.com/chan-9410057/all_p2.html
http://support372.rssing.com/browser.php?indx=9410057&item=23
If you are using .Net Framework 4.0 then the resolution is to modify the “machine.config” file at:
%WINDIR%\Microsoft.NET\Framework\v4.0.xxxxx\ CONFIG -> for x86
%WINDIR%\Microsoft.NET\Framework64\v4.0.xxxxx\CONFIG -> for x64
If you are using .Net Framework 3.5 then the resolution is to modify the “machine.config” file at:
%WINDIR%\Microsoft.NET\Framework\v2.0.xxxxx\ CONFIG -> for x86
%WINDIR%\Microsoft.NET\Framework64\v2.0.xxxxx\CONFIG -> for x64
Here is the entry that you need to make at the "machine.config" file for supporting SHA256CryptoServiceProvider, SHA256Cng, SHA384CryptoServiceProvider, SHA384Cng, SHA512CryptoServiceProvider, and SHA512Cng.
<mscorlib>
<cryptographySettings>
<cryptoNameMapping>
<cryptoClasses>
<cryptoClass SHA256CSP="System.Security.Cryptography.SHA256CryptoServiceProvider, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA256CNG="System.Security.Cryptography.SHA256Cng, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA384CSP="System.Security.Cryptography.SHA384CryptoServiceProvider, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA384CNG="System.Security.Cryptography.SHA384Cng, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA512CSP="System.Security.Cryptography.SHA512CryptoServiceProvider, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA512CNG="System.Security.Cryptography.SHA512Cng, System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</cryptoClasses>
<nameEntry name="SHA256" class="SHA256CSP" />
<nameEntry name="SHA256CryptoServiceProvider" class="SHA256CSP" />
<nameEntry name="System.Security.Cryptography.SHA256CryptoServiceProvider" class="SHA256CSP" />
<nameEntry name="SHA256Next" class="SHA256CNG" />
<nameEntry name="SHA256Cng" class="SHA256CNG" />
<nameEntry name="System.Security.Cryptography.SHA256Cng" class="SHA256CNG" />
<nameEntry name="SHA384" class="SHA384CSP" />
<nameEntry name="SHA384CryptoServiceProvider" class="SHA384CSP" />
<nameEntry name="System.Security.Cryptography.SHA384CryptoServiceProvider" class="SHA384CSP" />
<nameEntry name="SHA384Next" class="SHA384CNG" />
<nameEntry name="SHA384Cng" class="SHA384CNG" />
<nameEntry name="System.Security.Cryptography.SHA384Cng" class="SHA384CNG" />
<nameEntry name="SHA512" class="SHA512CSP" />
<nameEntry name="SHA512CryptoServiceProvider" class="SHA512CSP" />
<nameEntry name="System.Security.Cryptography.SHA512CryptoServiceProvider" class="SHA512CSP" />
<nameEntry name="SHA512Next" class="SHA512CNG" />
<nameEntry name="SHA512Cng" class="SHA512CNG" />
<nameEntry name="System.Security.Cryptography.SHA512Cng" class="SHA512CNG" />
</cryptoNameMapping>
<oidMap>
<oidEntry OID="2.16.840.1.101.3.4.2.1" name="SHA256" />
<oidEntry OID="2.16.840.1.101.3.4.2.1" name="SHA256Next" />
<oidEntry OID="2.16.840.1.101.3.4.2.2" name="SHA384" />
<oidEntry OID="2.16.840.1.101.3.4.2.2" name="SHA384Next" />
<oidEntry OID="2.16.840.1.101.3.4.2.3" name="SHA512" />
<oidEntry OID="2.16.840.1.101.3.4.2.3" name="SHA512Next" />
</oidMap>
</cryptographySettings>
</mscorlib>
And here: https://help.relativity.com/9.2/Content/Installing_and_Upgrading/Relativity_installation.htm
Use this procedure to update the machine.config file:
Log in to your agent or web server.
Navigate to the machine.config file in the following directory:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config
Open the machine.config file in a text editor, and add the following code after the </system.web> element:
<mscorlib>
<cryptographySettings>
<cryptoNameMapping>
<cryptoClasses>
<cryptoClass SHA256CNG="System.Security.Cryptography.SHA256Cng, System.Core, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
<cryptoClass SHA512CNG="System.Security.Cryptography.SHA512Cng, System.Core, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
</cryptoClasses>
<nameEntry name="SHA256" class="SHA256CNG" />
<nameEntry name="SHA-256" class="SHA256CNG" />
<nameEntry name="System.Security.Cryptography.SHA256" class="SHA256CNG" />
<nameEntry name="SHA512" class="SHA512CNG" />
<nameEntry name="SHA-512" class="SHA512CNG" />
<nameEntry name="System.Security.Cryptography.SHA512" class="SHA512CNG" />
<nameEntry name="SHA256Managed" class="SHA256CNG" />
<nameEntry name="System.Security.Cryptography.SHA256Managed" class="SHA256CNG" />
<nameEntry name="SHA512Managed" class="SHA512CNG" />
<nameEntry name="System.Security.Cryptography.SHA512Managed" class="SHA512CNG" />
</cryptoNameMapping>
</cryptographySettings>
</mscorlib>
It looks to me like the issue itself is in mscorlib in NetCore not in Azure or PowerShell per se.
I do not know enough C# or .Net to fix it but it looks like you can work around it on Windows but I am not able to find workaround in Linux.
Additional Overload definition from Desktop Library:
PS /> $authContext.AcquireToken
OverloadDefinitions
-------------------
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential userCredential)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserAssertion userAssertion)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential clientCredential)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate clientCertificate)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertion clientAssertion)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, uri redirectUri)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, uri redirectUri, Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior promptBehavior)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, uri redirectUri, Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior promptBehavior, Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier userId)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, uri redirectUri, Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior promptBehavior, Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier userId, string extraQueryParameters)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential clientCredential, Microsoft.IdentityModel.Clients.ActiveDirectory.UserAssertion userAssertion)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate clientCertificate, Microsoft.IdentityModel.Clients.ActiveDirectory.UserAssertion userAssertion)
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertion clientAssertion, Microsoft.IdentityModel.Clients.ActiveDirectory.UserAssertion userAssertion)
This is the one we use I think:
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult AcquireToken(string resource, string clientId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential userCredential)
Does that help?
This flow not supported in ADAL for .net core:
https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Acquiring-tokens-with-username-and-password
AquireToken overview can be found here:
https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Acquiring-a-token-return-AuthenticationResult-and-possibly-UserInfo
@henrik-me Which I hope I explained why above ;-)
@cblackuk you did, thanks for the detailed explanation. I just wanted to point directly to the source.
@cblackuk @henrik-me -Credential
is removed from the User parameter set (not Service Principal set) for NetCore in 0.12.0