Skip to content

Commit 28ea1a2

Browse files
committed
Merge pull request #899 from hovsepm/psget
Added AzureLogin cmdlets
2 parents d725792 + ecf227b commit 28ea1a2

File tree

9 files changed

+618
-7
lines changed

9 files changed

+618
-7
lines changed

src/Common/Commands.ResourceManager.Common/Commands.ResourceManager.Common.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,22 @@
166166
</Compile>
167167
<Compile Include="AzureRMCmdlet.cs" />
168168
<Compile Include="Properties\AssemblyInfo.cs" />
169+
<Compile Include="Properties\Resources.Designer.cs">
170+
<AutoGen>True</AutoGen>
171+
<DesignTime>True</DesignTime>
172+
<DependentUpon>Resources.resx</DependentUpon>
173+
</Compile>
174+
<Compile Include="RMProfileClient.cs" />
169175
<None Include="packages.config">
170176
<SubType>Designer</SubType>
171177
</None>
172178
</ItemGroup>
179+
<ItemGroup>
180+
<EmbeddedResource Include="Properties\Resources.resx">
181+
<Generator>ResXFileCodeGenerator</Generator>
182+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
183+
</EmbeddedResource>
184+
</ItemGroup>
173185
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
174186
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
175187
<Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />

src/Common/Commands.ResourceManager.Common/Properties/Resources.Designer.cs

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 2.0
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">2.0</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
<value>[base64 mime encoded serialized .NET Framework object]</value>
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27+
<comment>This is a comment</comment>
28+
</data>
29+
30+
There are any number of "resheader" rows that contain simple
31+
name/value pairs.
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
37+
mimetype set.
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
41+
extensible. For a given mimetype the value must be set accordingly:
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
45+
read any of the formats listed below.
46+
47+
mimetype: application/x-microsoft.net.object.binary.base64
48+
value : The object must be serialized with
49+
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50+
: and then encoded with base64 encoding.
51+
52+
mimetype: application/x-microsoft.net.object.soap.base64
53+
value : The object must be serialized with
54+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55+
: and then encoded with base64 encoding.
56+
57+
mimetype: application/x-microsoft.net.object.bytearray.base64
58+
value : The object must be serialized into a byte array
59+
: using a System.ComponentModel.TypeConverter
60+
: and then encoded with base64 encoding.
61+
-->
62+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63+
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64+
<xsd:element name="root" msdata:IsDataSet="true">
65+
<xsd:complexType>
66+
<xsd:choice maxOccurs="unbounded">
67+
<xsd:element name="metadata">
68+
<xsd:complexType>
69+
<xsd:sequence>
70+
<xsd:element name="value" type="xsd:string" minOccurs="0" />
71+
</xsd:sequence>
72+
<xsd:attribute name="name" use="required" type="xsd:string" />
73+
<xsd:attribute name="type" type="xsd:string" />
74+
<xsd:attribute name="mimetype" type="xsd:string" />
75+
<xsd:attribute ref="xml:space" />
76+
</xsd:complexType>
77+
</xsd:element>
78+
<xsd:element name="assembly">
79+
<xsd:complexType>
80+
<xsd:attribute name="alias" type="xsd:string" />
81+
<xsd:attribute name="name" type="xsd:string" />
82+
</xsd:complexType>
83+
</xsd:element>
84+
<xsd:element name="data">
85+
<xsd:complexType>
86+
<xsd:sequence>
87+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88+
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89+
</xsd:sequence>
90+
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91+
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92+
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93+
<xsd:attribute ref="xml:space" />
94+
</xsd:complexType>
95+
</xsd:element>
96+
<xsd:element name="resheader">
97+
<xsd:complexType>
98+
<xsd:sequence>
99+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100+
</xsd:sequence>
101+
<xsd:attribute name="name" type="xsd:string" use="required" />
102+
</xsd:complexType>
103+
</xsd:element>
104+
</xsd:choice>
105+
</xsd:complexType>
106+
</xsd:element>
107+
</xsd:schema>
108+
<resheader name="resmimetype">
109+
<value>text/microsoft-resx</value>
110+
</resheader>
111+
<resheader name="version">
112+
<value>2.0</value>
113+
</resheader>
114+
<resheader name="reader">
115+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116+
</resheader>
117+
<resheader name="writer">
118+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119+
</resheader>
120+
<data name="TenantNotFound" xml:space="preserve">
121+
<value>Tenant '{0}' was not found. Please verify that your account has access to this tenant.</value>
122+
</data>
123+
</root>
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Hyak.Common;
16+
using Microsoft.Azure.Common.Authentication;
17+
using Microsoft.Azure.Common.Authentication.Factories;
18+
using Microsoft.Azure.Common.Authentication.Models;
19+
using Microsoft.Azure.Subscriptions;
20+
using System;
21+
using System.Collections.Generic;
22+
using System.Linq;
23+
using System.Management.Automation;
24+
using System.Security;
25+
26+
namespace Microsoft.Azure.Commands.ResourceManager.Common
27+
{
28+
public class RMProfileClient
29+
{
30+
private AzureRMProfile _profile;
31+
public Action<string> WarningLog;
32+
33+
public RMProfileClient(AzureRMProfile profile)
34+
{
35+
_profile = profile;
36+
}
37+
38+
public AzureRMProfile Login(AzureAccount account, AzureEnvironment environment, string tenantId, string subscriptionId, SecureString password)
39+
{
40+
AzureSubscription newSubscription = null;
41+
AzureTenant newTenant = new AzureTenant();
42+
43+
// (tenant and subscription are present) OR
44+
// (tenant is present and subscription is not provided)
45+
if (!string.IsNullOrEmpty(tenantId))
46+
{
47+
newTenant.Id = new Guid(tenantId);
48+
ShowDialog promptBehavior = password == null ? ShowDialog.Always : ShowDialog.Never;
49+
TryGetTenantSubscription(account, environment, tenantId, subscriptionId, password, promptBehavior, out newSubscription);
50+
}
51+
// (tenant is not provided and subscription is present) OR
52+
// (tenant is not provided and subscription is not provided)
53+
else
54+
{
55+
foreach(var tenant in ListAccountTenants(account, environment, password))
56+
{
57+
if (TryGetTenantSubscription(account, environment, tenant, subscriptionId, password, ShowDialog.Auto, out newSubscription))
58+
{
59+
newTenant.Id = new Guid(tenant);
60+
break;
61+
}
62+
}
63+
64+
}
65+
66+
if (newSubscription == null)
67+
{
68+
throw new PSInvalidOperationException("Subscription was not found.");
69+
}
70+
71+
_profile.DefaultContext = new AzureContext(newSubscription, account, environment, newTenant);
72+
73+
return _profile;
74+
}
75+
76+
private bool TryGetTenantSubscription(
77+
AzureAccount account,
78+
AzureEnvironment environment,
79+
string tenantId,
80+
string subscriptionId,
81+
SecureString password,
82+
ShowDialog promptBehavior,
83+
out AzureSubscription subscription)
84+
{
85+
var accessToken = AzureSession.AuthenticationFactory.Authenticate(
86+
account,
87+
environment,
88+
tenantId,
89+
password,
90+
promptBehavior);
91+
using (var subscriptionClient = AzureSession.ClientFactory.CreateCustomClient<SubscriptionClient>(
92+
new TokenCloudCredentials(accessToken.AccessToken),
93+
environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager)))
94+
{
95+
Subscriptions.Models.Subscription subscriptionFromServer = null;
96+
97+
try
98+
{
99+
if (subscriptionId != null)
100+
{
101+
subscriptionFromServer = subscriptionClient.Subscriptions.Get(subscriptionId).Subscription;
102+
}
103+
else
104+
{
105+
var subscriptions = subscriptionClient.Subscriptions.List().Subscriptions;
106+
if (subscriptions != null)
107+
{
108+
if (subscriptions.Count > 1)
109+
{
110+
WriteWarningMessage(string.Format(
111+
"Tenant '{0}' contains more than one subscription. First one will be selected for further use.",
112+
tenantId));
113+
}
114+
subscriptionFromServer = subscriptions.First();
115+
}
116+
}
117+
}
118+
catch (CloudException ex)
119+
{
120+
WriteWarningMessage(ex.Message);
121+
}
122+
123+
if (subscriptionFromServer != null)
124+
{
125+
subscription = new AzureSubscription
126+
{
127+
Id = new Guid(subscriptionFromServer.SubscriptionId),
128+
Account = accessToken.UserId,
129+
Environment = environment.Name,
130+
Name = subscriptionFromServer.DisplayName,
131+
Properties = new Dictionary<AzureSubscription.Property, string> { { AzureSubscription.Property.Tenants, accessToken.TenantId } }
132+
};
133+
return true;
134+
}
135+
136+
subscription = null;
137+
return false;
138+
}
139+
}
140+
141+
private string[] ListAccountTenants(AzureAccount account, AzureEnvironment environment, SecureString password)
142+
{
143+
ShowDialog promptBehavior = password == null ? ShowDialog.Always : ShowDialog.Never;
144+
145+
var commonTenantToken = AzureSession.AuthenticationFactory.Authenticate(account, environment,
146+
AuthenticationFactory.CommonAdTenant, password, promptBehavior);
147+
148+
using (var subscriptionClient = AzureSession.ClientFactory.CreateCustomClient<SubscriptionClient>(
149+
new TokenCloudCredentials(commonTenantToken.AccessToken),
150+
environment.GetEndpointAsUri(AzureEnvironment.Endpoint.ResourceManager)))
151+
{
152+
return subscriptionClient.Tenants.List().TenantIds.Select(ti => ti.TenantId).ToArray();
153+
}
154+
}
155+
156+
private void WriteWarningMessage(string message)
157+
{
158+
if (WarningLog != null)
159+
{
160+
WarningLog(message);
161+
}
162+
}
163+
}
164+
}

src/Common/Commands.ResourceManager.Profile.Test/Commands.ResourceManager.Profile.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
</Reference>
179179
</ItemGroup>
180180
<ItemGroup>
181+
<Compile Include="LoginCmdletTests.cs" />
181182
<Compile Include="ProfileCmdletTests.cs" />
182183
<Compile Include="Properties\AssemblyInfo.cs" />
183184
</ItemGroup>

0 commit comments

Comments
 (0)