Skip to content

Commit 9d9e9e7

Browse files
committed
Enabling the first time scenario for vault credentials
1 parent dc143bc commit 9d9e9e7

File tree

6 files changed

+147
-21
lines changed

6 files changed

+147
-21
lines changed

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/PSRecoveryServicesClient/PSRecoveryServicesVaultExtendedInfoClient.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@ public async Task<ResourceExtendedInformation> GetExtendedInfo()
3939
/// </summary>
4040
/// <param name="extendedInfoArgs">extended info to be created</param>
4141
/// <returns>Vault Extended Information</returns>
42-
public async Task<ResourceExtendedInformation> CreateExtendedInfo(ResourceExtendedInformationArgs extendedInfoArgs)
42+
public OperationResponse CreateExtendedInfo(ResourceExtendedInformationArgs extendedInfoArgs)
4343
{
44-
ResourceExtendedInformationResponse response = await this.GetSiteRecoveryClient().VaultExtendedInfo.CreateExtendedInfoAsync(extendedInfoArgs, this.GetRequestHeaders(false));
45-
46-
return response.ResourceExtendedInformation;
44+
return this.GetSiteRecoveryClient().VaultExtendedInfo.CreateExtendedInfo(extendedInfoArgs, this.GetRequestHeaders(false));
4745
}
4846
}
4947
}

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/Service/GetVaultCredentialsFile.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@
1414

1515
using System;
1616
using System.Management.Automation;
17+
using System.Net;
1718
using System.Security.Cryptography.X509Certificates;
1819
using System.Threading.Tasks;
1920
using Microsoft.Azure.Commands.RecoveryServices.SiteRecovery;
2021
using Microsoft.Azure.Portal.HybridServicesCore;
2122
using Microsoft.Azure.Portal.RecoveryServices.Models.Common;
23+
using Microsoft.WindowsAzure;
2224
using Microsoft.WindowsAzure.Commands.Common;
2325
using Microsoft.WindowsAzure.Commands.Common.Models;
2426
using Microsoft.WindowsAzure.Management.RecoveryServices.Models;
2527
using Microsoft.WindowsAzure.Management.SiteRecovery.Models;
28+
using rpError = Microsoft.Azure.Commands.RecoveryServices.RestApiInfra;
2629

2730
namespace Microsoft.Azure.Commands.RecoveryServices
2831
{
@@ -166,30 +169,64 @@ private async Task<UploadCertificateResponse> UpdateVaultCertificate(X509Certifi
166169
/// <returns>key as string.</returns>
167170
private async Task<string> GetChannelIntegrityKey()
168171
{
169-
ResourceExtendedInformation extendedInformation;
172+
ResourceExtendedInformation extendedInformation = null;
170173
try
171174
{
172175
extendedInformation = await RecoveryServicesClient.GetExtendedInfo();
173176
}
174-
catch (Exception)
177+
catch (Exception exception)
175178
{
176-
// TODO:devsri - Handle specific error rather than generic once
177-
extendedInformation = new ResourceExtendedInformation();
179+
try
180+
{
181+
CloudException cloudException = exception as CloudException;
182+
183+
if (cloudException != null && cloudException.Response != null && !string.IsNullOrEmpty(cloudException.Response.Content))
184+
{
185+
rpError.Error error = (rpError.Error)Utilities.Deserialize<rpError.Error>(cloudException.Response.Content);
186+
if (error.ErrorCode.Equals(RpErrorCode.ResourceExtendedInfoNotFound.ToString(), StringComparison.InvariantCultureIgnoreCase))
187+
{
188+
extendedInformation = new ResourceExtendedInformation();
189+
}
190+
}
191+
}
192+
catch (Exception ex)
193+
{
194+
this.HandleException(ex);
195+
}
178196
}
179197

180198
ResourceExtendedInfo extendedInfo = Utilities.Deserialize<ResourceExtendedInfo>(extendedInformation.ExtendedInfo);
181199

182200
if (extendedInfo == null)
183201
{
184-
ResourceExtendedInformationArgs extendedInfoArgs = extendedInfo.Translate();
185-
extendedInformation = await RecoveryServicesClient.CreateExtendedInfo(extendedInfoArgs);
186-
187-
extendedInfo = Utilities.Deserialize<ResourceExtendedInfo>(extendedInformation.ExtendedInfo);
202+
extendedInfo = this.CreateVaultExtendedInformatino();
188203
}
189204

190205
return extendedInfo.ChannelIntegrityKey;
191206
}
192207

208+
/// <summary>
209+
/// Method to create the extended info for the vault.
210+
/// </summary>
211+
/// <returns>returns the object as task</returns>
212+
private ResourceExtendedInfo CreateVaultExtendedInformatino()
213+
{
214+
ResourceExtendedInfo extendedInfo = null;
215+
try
216+
{
217+
extendedInfo = new ResourceExtendedInfo();
218+
extendedInfo.GenerateSecurityInfo();
219+
ResourceExtendedInformationArgs extendedInfoArgs = extendedInfo.Translate();
220+
RecoveryServicesClient.CreateExtendedInfo(extendedInfoArgs);
221+
}
222+
catch (Exception exception)
223+
{
224+
this.HandleException(exception);
225+
}
226+
227+
return extendedInfo;
228+
}
229+
193230
/// <summary>
194231
/// Method to generate the credential file content
195232
/// </summary>

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/lib/PSContracts.cs

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,48 @@ public enum VaultStatus
7979
Removing
8080
}
8181

82+
/// <summary>
83+
/// The types of crypto algorithms
84+
/// </summary>
85+
public enum CryptoAlgorithm
86+
{
87+
/// <summary>
88+
/// The asymmetric key based RSA 2048 algorithm.
89+
/// </summary>
90+
RSAPKCS1V17,
91+
92+
/// <summary>
93+
/// The asymmetric key based RSA 2048 algorithm.
94+
/// </summary>
95+
RSAPKCS1V15,
96+
97+
/// <summary>
98+
/// The symmetric key based AES algorithm with key size 256 bits.
99+
/// </summary>
100+
AES256,
101+
102+
/// <summary>
103+
/// The symmetric key based SHA 256 Algorithm
104+
/// </summary>
105+
HMACSHA256,
106+
107+
/// <summary>
108+
/// When no algorithm is used.
109+
/// </summary>
110+
None
111+
}
112+
113+
/// <summary>
114+
/// The RP service error code that needs to be handled by portal.
115+
/// </summary>
116+
public enum RpErrorCode
117+
{
118+
/// <summary>
119+
/// The error code sent by RP if the Resource extended info doesn't exists.
120+
/// </summary>
121+
ResourceExtendedInfoNotFound
122+
}
123+
82124
/// <summary>
83125
/// Constant definition
84126
/// </summary>
@@ -94,10 +136,15 @@ public class Constants
94136
/// </summary>
95137
public const string VaultCredentialVersion = "1.0";
96138

139+
/// <summary>
140+
/// The version of Extended resource info.
141+
/// </summary>
142+
public const string VaultSecurityInfoVersion = "1.0";
143+
97144
/// <summary>
98145
/// extended information version.
99146
/// </summary>
100-
public const string VaultExtendedInfVersion = "V2014_09";
147+
public const string VaultExtendedInfoContractVersion = "V2014_09";
101148

102149
/// <summary>
103150
/// A valid value for the string field Microsoft.WindowsAzure.CloudServiceManagement.resource.OperationStatus.Type
@@ -327,6 +374,27 @@ public class TaskStatus
327374
}
328375
}
329376

377+
//// TODO: Remove this once we get nuget
378+
namespace Microsoft.Azure.Commands.RecoveryServices.RestApiInfra
379+
{
380+
/// <summary>
381+
/// Class to define the error for RP
382+
/// </summary>
383+
[SuppressMessage(
384+
"Microsoft.StyleCop.CSharp.MaintainabilityRules",
385+
"SA1402:FileMayOnlyContainASingleClass",
386+
Justification = "Keeping all contracts together.")]
387+
[DataContract(Namespace = "http://schemas.microsoft.com/wars")]
388+
public class Error
389+
{
390+
/// <summary>
391+
/// Gets or sets the value for the error as string.
392+
/// </summary>
393+
[DataMember]
394+
public string ErrorCode { get; set; }
395+
}
396+
}
397+
330398
namespace Microsoft.Azure.Portal.RecoveryServices.Models.Common
331399
{
332400
/// <summary>
@@ -563,24 +631,33 @@ public class ResourceExtendedInfo
563631
/// <summary>
564632
/// Returns the Xml representation of this object.
565633
/// </summary>
566-
/// <param name="etag">string to be used as unique identifier for the request</param>
567634
/// <returns>the xml as string</returns>
568-
public ResourceExtendedInformationArgs Translate(string etag = null)
635+
public ResourceExtendedInformationArgs Translate()
569636
{
570-
string serializedInfo = Utilities.Serialize<ResourceExtendedInfo>(this);
571-
if (string.IsNullOrEmpty(etag))
637+
if (string.IsNullOrEmpty(this.Etag))
572638
{
573-
etag = Guid.NewGuid().ToString();
639+
this.Etag = Guid.NewGuid().ToString();
574640
}
575641

642+
string serializedInfo = Utilities.Serialize<ResourceExtendedInfo>(this);
576643
ResourceExtendedInformationArgs extendedInfoArgs = new ResourceExtendedInformationArgs(
577-
Constants.VaultExtendedInfVersion,
644+
Constants.VaultExtendedInfoContractVersion,
578645
serializedInfo,
579-
etag);
646+
this.Etag);
580647

581648
return extendedInfoArgs;
582649
}
583650

651+
/// <summary>
652+
/// Method to generate security information
653+
/// </summary>
654+
public void GenerateSecurityInfo()
655+
{
656+
this.ChannelIntegrityKey = Utilities.GenerateRandomKey(128);
657+
this.Version = Constants.VaultSecurityInfoVersion;
658+
this.Algorithm = CryptoAlgorithm.None.ToString();
659+
}
660+
584661
#endregion
585662
}
586663
}

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/lib/PSObjects.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ private string ParseStatus(ResourceOperationStatus operationStatus)
853853
/// <summary>
854854
/// Method to extract vault id
855855
/// </summary>
856-
/// <param name="OutputItems">the output item from vault</param>
856+
/// <param name="outputItems">the output item from vault</param>
857857
/// <returns>returns the vault id as string</returns>
858858
private string ParseVaultId(IList<OutputItem> outputItems)
859859
{

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/lib/Utilities.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using System;
1616
using System.IO;
1717
using System.Runtime.Serialization;
18+
using System.Security.Cryptography;
1819
using Microsoft.Azure.Portal.RecoveryServices.Models.Common;
1920

2021
namespace Microsoft.Azure.Commands.RecoveryServices
@@ -121,5 +122,18 @@ public static string GetDefaultPath()
121122

122123
return path;
123124
}
125+
126+
/// <summary>
127+
/// Generate cryptographically random key of given bit size.
128+
/// </summary>
129+
/// <param name="size">size of the key to be generated</param>
130+
/// <returns>the key</returns>
131+
public static string GenerateRandomKey(int size)
132+
{
133+
byte[] key = new byte[(int)size / 8];
134+
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
135+
crypto.GetBytes(key);
136+
return Convert.ToBase64String(key);
137+
}
124138
}
125139
}

0 commit comments

Comments
 (0)