C# Azure Management REST API - Bind Certificate to App Service Custom Domain - azure

I can create a custom domain using the Azure Management REST API, and I can create an App Service Managed certificate, which is associated with the custom domain (I think). Maybe not. However, under custom domains in my app service, it shows that I need to add a binding.
Here is the certificate:
https://management.azure.com/subscriptions/xxx-xxx-479a-bb9f-4c7e01d9a379/resourceGroups/MyResourceGroup/providers/Microsoft.Web/sites/xxx20211028195113/hostNameBindings/my.site?api-version=2016-08-01
and
https://management.azure.com/subscriptions/xxx-xxx-479a-bb9f-4c7e01d9a379/resourceGroups/MyResourceGroup/providers/Microsoft.Web/certificates/my.site?api-version=2021-02-01
I used the first end-point to create the custom domain, and the second end-point to create the certificate. I'm not sure how to bind the certificate to the custom domain. I expected the call to create certificate to do that for me since I included the serverFarm in the request body, but it didn't work.
I want to use the Azure Management API to bind the certificate to the custom domain. How can I do that? which endpoint should I use and what values need to be set in the request body?
Any help would be appreciated. Thanks.
For my full code reference, see my other post here:
C# .Net Azure Management REST API - Add App Service Managed Certificate - Response = Not Found
EDIT: Showing the Complete Answer
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MyShoppingCart.Helpers.ManagementLibrarySample
{
public class ManagementLibrarySample
{
static string _ClientId = Startup.StaticConfig.GetValue<string>("Azure:ClientId");
static string _ClientKey = Startup.StaticConfig.GetValue<string>("Azure:ClientSecret");
static string _TenantId = Startup.StaticConfig.GetValue<string>("Azure:TenantId");
static string _SubscriptionId = Startup.StaticConfig.GetValue<string>("Azure:SubscriptionId");
static string _ResourceGroupName = Startup.StaticConfig.GetValue<string>("Azure:ResourceGroupName");
static string _AlternateResourceGroupName = Startup.StaticConfig.GetValue<string>("Azure:AlternateResourceGroupName");
static string _AppName = Startup.StaticConfig.GetValue<string>("Azure:AppName");
static string _AppServicePlanName = Startup.StaticConfig.GetValue<string>("Azure:AppServicePlanName");
static Uri _baseURI = new Uri($"https://management.azure.com/");
private static string GetAccessToken()
{
var context = new AuthenticationContext("https://login.windows.net/" + _TenantId);
ClientCredential clientCredential = new ClientCredential(_ClientId, _ClientKey);
var tokenResponse = context.AcquireTokenAsync(_baseURI.ToString(), clientCredential).Result;
return tokenResponse.AccessToken;
}
public static async Task<bool> CreateCustomDomainAndCertificate(string sHostName)
{
bool ret = false;
HttpResponseMessage responseMessage = await CreateCustomDomain(sHostName);
if (responseMessage.IsSuccessStatusCode)
{
responseMessage = await CreateAppManagedCertificate(sHostName);
/*
it can take a good 5 minutes to create the certificate
but you get the 202 status code right away.
You cannot bind the certificate to the custom domain
name until after the certificate actually exists.
*/
if ((long)responseMessage.StatusCode == 202)// Accepted
{
DateTime dtStart = DateTime.Now;
while ((long)responseMessage.StatusCode != 200 && DateTime.Now < dtStart.AddMinutes(10))
{//Wait until the certificate has been created, up to 10 minutes
Thread.Sleep(60000);//1 minute
responseMessage = await BindCertificateToCustomDomain(sHostName);
}
if ((long)responseMessage.StatusCode == 200)
ret = true;
}
}
return ret;
}
private static async Task<HttpResponseMessage> CreateCustomDomain(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/sites/{_AppName}/hostNameBindings/{sHostName}?api-version=2016-08-01";
string body = $"{{\"properties\": {{\"azureResourceName\": \"{_AppName}\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
private static async Task<HttpResponseMessage> CreateAppManagedCertificate(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/certificates/{sHostName}?api-version=2021-02-01";
string serverFarm = $"/subscriptions/{_SubscriptionId}/resourceGroups/{_AlternateResourceGroupName}/providers/Microsoft.Web/serverfarms/{_AppServicePlanName}";
string body = $"{{\"location\": \"West US\", \"properties\": {{\"canonicalName\": \"{sHostName}\", \"hostNames\": [\"{sHostName}\"], \"serverFarmId\": \"{serverFarm}\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
private static async Task<HttpResponseMessage> BindCertificateToCustomDomain(string sHostName)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
string requestURl = _baseURI + $"subscriptions/{_SubscriptionId}/resourceGroups/{_ResourceGroupName}/providers/Microsoft.Web/sites/{_AppName}?api-version=2016-08-01";
string serverFarm = $"/subscriptions/{_SubscriptionId}/resourceGroups/{_AlternateResourceGroupName}/providers/Microsoft.Web/serverfarms/{_AppServicePlanName}";
string body = $"{{\"location\": \"West US\", \"properties\": {{\"HostNameSslStates\": [ {{ \"SslState\" : \"1\", \"ToUpdate\" : \"True\", \"Name\": \"{sHostName}\"}}]}}, \"kind\": \"app\", \"location\": \"West US\", \"tags\" : {{\"hidden-related:{serverFarm}\": \"empty\"}}}}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
return await client.PutAsync(requestURl, stringContent);
}
}
}
}

How can I use the Management API to secure the custom domain with the
app service managed certificate?
Thanks #David.Warwick for the confirmation,
As we have discussed to achieve the above requirement we have to use the below Rest API .
You can try with PUT method for binding SSL certificate with Custom domain.
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Web/sites/{snapshotName}?api-version={api-version}
For more information please refer this SO THREAD

Related

How to call an Azure Function App API with Easy-Auth Enables using Active Directory from a C# Client

I have an Azure Function App with Azure Active Directory configured but when I call if from my client I keep getting an Unauthorized response.
I have tried a couple different scenarios but nothing worked. Below is a snippet of the last bit of code that I tried.
///
var #params2 = new NameValueCollection
{
{"grant_type", "client_credentials"},
{"client_id", $"{ClientId}"},
{"client_secret", $"{ClientSecret}"},
{"username", userId},
{"resource", "https://management.azure.com/"}
};
var queryString2 = HttpUtility.ParseQueryString(string.Empty);
queryString2.Add(#params2);
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"grant_type", "client_credentials"},
{"client_id", ClientId},
{"client_secret", ClientSecret},
{"username", userId}
});
var authorityUri2 = $"{string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant).TrimEnd('/')}/oauth2/token";
//var authorityUri2 = $"https://login.microsoftonline.com/{Tenant}/v2.0/.well-known/openid-configuration";
var authUri2 = String.Format("{0}?{1}", authorityUri2, queryString2);
var client2 = new HttpClient();
var message = client2.PostAsync(authorityUri2, content).Result;
//var message = client2.GetAsync(authorityUri2).Result;
var response = message.Content.ReadAsStringAsync().Result;
dynamic values=null;
try
{
values = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
}
catch
{
values = response;
}
var AuthToken2 = values["access_token"];
client2.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken2);
HttpResponseMessage response2 = await client2.GetAsync(AppBaseAddress.TrimEnd('/') + "/api/AADIntegration");
if (response.IsSuccessStatusCode)
{
// Read the response and data-bind to the GridView to display To Do items.
string s = await response.Content.ReadAsStringAsync();
log.LogInformation($"Success while getting / api / AADIntegration : {s}");
return (ActionResult)new OkObjectResult(s);
}
else
{
string failureDescription = await response.Content.ReadAsStringAsync();
log.LogInformation($"An error occurred while getting / api / AADIntegration : {response.ReasonPhrase}\n {failureDescription}");
return (ActionResult)new OkObjectResult(failureDescription);
}
Data should returned from the Function App.
For client_credentials grant flow your code seems little different. Here I am giving you exact sample for azure function. Just plug and play :))
Example contains:
How would you get token using client_credentials flow
Getting user list From Azure Active Directory tenant using above
token
Access Token Class:
public class AccessTokenClass
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string resource { get; set; }
public string scope { get; set; }
public string access_token { get; set; }
}
Reference To Add:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Collections.Generic;
using System.Net.Http.Headers;
Azure Function Body:
public static class FunctionGetUserList
{
[FunctionName("FunctionGetUserList")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
try
{
log.LogInformation("C# HTTP trigger function processed a request.");
//Token Request endpoint Just replace yourTennantId/Name
string tokenUrl = $"https://login.microsoftonline.com/yourTennantId/Name.onmicrosoft.com/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "b603c7bead87-Your_client_id-e6921e61f925",
["client_secret"] = "Vxf1SluKbgu4P-Your_client_Secret-F0Nf3wE5oGl/2XDSeZ=",
["resource"] = "https://graph.microsoft.com"
});
dynamic json;
AccessTokenClass results = new AccessTokenClass();
HttpClient client = new HttpClient();
var tokenResponse = await client.SendAsync(tokenRequest);
json = await tokenResponse.Content.ReadAsStringAsync();
results = JsonConvert.DeserializeObject<AccessTokenClass>(json);
var accessToken = results.access_token;
//Create Request To Server
using (HttpClient clientNew = new HttpClient())
{
//Pass Token on header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Get Data from API
var requestToAzureEndpoint = await client.GetAsync("https://graph.microsoft.com/v1.0/users");
if (requestToAzureEndpoint.IsSuccessStatusCode)
{
var result_string = await requestToAzureEndpoint.Content.ReadAsStringAsync();
dynamic responseResults = JsonConvert.DeserializeObject<dynamic>(result_string);
return new OkObjectResult(responseResults);
}
else
{
var result_string = await requestToAzureEndpoint.Content.ReadAsStringAsync();
return new OkObjectResult(result_string);
}
}
}
catch (Exception ex)
{
return new OkObjectResult(ex.Message);
}
}
}
Point To Remember
For Azure Active Directory List users access make sure you have following permission:
User.Read.All
Permission Type: Application
You can check here. See the screen shot for better understanding; make sure you have clicked "Grant admin consent for yourTenant" after adding permission.
Note: This is how you can access Azure Active Directory Token using Azure Function after that how to access resource using that token to a specific API endpoint efficiently.
Are you sure you have properly implemented this properly? It looks like a few of your parameters are wrong for the client credential flow. Please double check that you are properly following the client credential flow.
The client credential grant flow is documented here : https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
But for more information on getting this properly working in your function app, please refer to the blog below for more information/help on implementing this.
https://blogs.msdn.microsoft.com/ben/2018/11/07/client-app-calling-azure-function-with-aad/
The value of resource is not correct.
Replace {"resource", "https://management.azure.com/"} with {"resource", $"{ClientId}"}

Unable to manual trigger my Azure Timer Trigger using httpclient post request

https://learn.microsoft.com/en-us/azure/azure-functions/functions-manually-run-non-http
I am trying to manual trigger my Azure Timer function App created in 2.0 and developed in .net core 2.0.
When I try to hit the url I get 403 error.
apikey I pass is picked from :
As the article you provided, you need to use _master key under Manage and Host key
I use the following class in my integration tests against service bus triggered Azure Functions.
class AzureFunctionCaller
{
private readonly HttpClient _httpClient;
private readonly string _functionUri;
public AzureFunctionCaller(string functionName)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("x-functions-key","<Key>");
_functionUri = $"<FUNCTION_ENDPOINT>/admin/functions/{functionName}";
}
public async Task CallViaAdminEndpoint(string content)
{
var httpContent = new StringContent(content, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(_functionUri, httpContent);
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Response content: {responseContent}");
}
}
Then you must send the data in a format where you place the content in "input" object.
var azureFunctionCaller = new AzureFunctionCaller("<FunctionName>");
var obj = new
{
... // properties you want to send
};
var jsonContent = JsonConvert.SerializeObject(new
{
input = JsonConvert.SerializeObject(obj)
});
await azureFunctionCaller.CallViaAdminEndpoint(jsonContent);`
To explain the input property, here is how the same call looks like in postman:

Azure AD B2C Custom User Attributes

I'm new to the Azure B2C world. I'm attempting to create a Custom User attribute to store data for our application. I've created it in the Azure portal and assigned it to my Signup/SignIn policy. However, I want to be able to update/read this value programtically. I've been going down the route of using Graph API and registering Extensions. So two questions:
1) Are extensions/custom attributes the same thing?
2) I've tried this code and the returned extensions are always empty:
public void RegisterExtension()
{
string myRegisteredAppObjectId = "<>";
string json = #"{
""name"": ""My Custom Attribute"",
""dataType"": ""String"",
""targetObjects"": [
""User""
]
}";
B2CGraphClient b2CGraphClient = new B2CGraphClient();
b2CGraphClient.RegisterExtension(myRegisteredAppObjectId, json);
var extensions = JsonConvert.DeserializeObject(b2CGraphClient.GetExtensions(myRegisteredAppObjectId).Result);
}
B2CGraphClient.cs
public class B2CGraphClient
{
private string clientId { get; set; }
private string clientSecret { get; set; }
private string tenant { get; set; }
private AuthenticationContext authContext;
private ClientCredential credential;
public B2CGraphClient(string clientId, string clientSecret, string tenant)
{
// The client_id, client_secret, and tenant are pulled in from the App.config file
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tenant = tenant;
// The AuthenticationContext is ADAL's primary class, in which you indicate the direcotry to use.
this.authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
// The ClientCredential is where you pass in your client_id and client_secret, which are
// provided to Azure AD in order to receive an access_token using the app's identity.
this.credential = new ClientCredential(clientId, clientSecret);
}
public async Task<string> DeleteUser(string objectId)
{
return await SendGraphDeleteRequest("/users/" + objectId);
}
public async Task<string> RegisterExtension(string objectId, string body)
{
return await SendGraphPostRequest("/applications/" + objectId + "/extensionProperties", body);
}
public async Task<string> GetExtensions(string appObjectId)
{
return await SendGraphGetRequest("/applications/" + appObjectId + "/extensionProperties", null);
}
private async Task<string> SendGraphPostRequest(string api, string json)
{
// NOTE: This client uses ADAL v2, not ADAL v4
AuthenticationResult result = authContext.AcquireToken(Globals.aadGraphResourceId, credential);
HttpClient http = new HttpClient();
string url = Globals.aadGraphEndpoint + tenant + api + "?" + Globals.aadGraphVersion;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("POST " + url);
Console.WriteLine("Authorization: Bearer " + result.AccessToken.Substring(0, 80) + "...");
Console.WriteLine("Content-Type: application/json");
Console.WriteLine("");
Console.WriteLine(json);
Console.WriteLine("");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine((int)response.StatusCode + ": " + response.ReasonPhrase);
Console.WriteLine("");
return await response.Content.ReadAsStringAsync();
}
public async Task<string> SendGraphGetRequest(string api, string query)
{
// First, use ADAL to acquire a token using the app's identity (the credential)
// The first parameter is the resource we want an access_token for; in this case, the Graph API.
AuthenticationResult result = authContext.AcquireToken("https://graph.windows.net", credential);
// For B2C user managment, be sure to use the 1.6 Graph API version.
HttpClient http = new HttpClient();
string url = "https://graph.windows.net/" + tenant + api + "?" + Globals.aadGraphVersion;
if (!string.IsNullOrEmpty(query))
{
url += "&" + query;
}
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("GET " + url);
Console.WriteLine("Authorization: Bearer " + result.AccessToken.Substring(0, 80) + "...");
Console.WriteLine("");
// Append the access token for the Graph API to the Authorization header of the request, using the Bearer scheme.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine((int)response.StatusCode + ": " + response.ReasonPhrase);
Console.WriteLine("");
return await response.Content.ReadAsStringAsync();
}
}
Of course, myRegisteredAppObjectId has a valid GUID in it.
Thanks
Are extensions/custom attributes the same thing?
Based on my test, extensions is the same thing as custom attributes.
I've tried this code and the returned extensions are always empty:
I add the custom propery MyCustomAttribute following this tutorial and use a custom attribute in my policy. You could refer to my test steps.
I download the B2C-GraphAPI-DotNet project from Github. Using following code to the custom attribute
var applications = client.GetApplications("$filter=startswith(displayName, 'b2c-extensions-app')").Result
var extension = client.GetExtensions(objectId).Result //objectId from the applications result.
Then we could get the custom properties from the extension.
Then you can then treat that attribute the same way you treat any other property on a user object
Such as create a user:
var jsonObject = new JObject
{
{"accountEnabled", true},
{"country", "US"},
{"creationType", "LocalAccount"},
{"displayName", "Tomsun"},
{"passwordPolicies", "DisablePasswordExpiration,DisableStrongPassword"},
{ "extension_42ba0de8530a4b5bbe6dad21fe6ef092_MyCustomAttribute","test2"}, //custom propery
{"passwordProfile", new JObject
{
{"password", "!QAZ1234wer"},
{"forceChangePasswordNextLogin", true}
} },
{"signInNames", new JArray
{
new JObject
{
{"value","tom1#example.com"},
{"type", "emailAddress"}
}
}
}
};
string user = client.CreateUser(jsonObject.ToString()).Result;
Query a user
var user = client.GetUserByObjectId(objectId).Result; //user objectId
Update a user
var jsonUpdate = new JObject
{
{ "extension_42ba0de8530a4b5bbe6dad21fe6ef092_MyCustomAttribute","testx"}
};
var updateuser = client.UpdateUser("objectId", jsonObject2.ToString()).Result; //UserObject Id

How to Submit Azure AD B2C NEW User Submission in MVC App

Loving Azure AD B2C... Looking forward to when it is out of preview!!!
Have a special case I need help putting my head around.
I have a page where I capture new email addresses via a web form.
After adding that email to my mailing list, I want to then create an AD B2C account automatically without making the user click any additional buttons using my ASP.NET MVC Site.
In reading the Article at: https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-graph-dotnet/
I see that it is possible to add a new user using the Graph API.
However, this example is written using a cmd program.
Does anyone know if there is some sample code to allow me to insert a user into AD B2C inside an MVC controller?
Heres some sample code on how I do it from ASP.Net MVC. Remeber that you need to include ClientId and Clientsecret (they are separate from the ASP.Net webapp) as explained in the article you mention. Code from controller--helperclass:
UserController:
// POST: User/Create
[HttpPost]
public async Task<ActionResult> Create(b2cuser usr)
{
try
{
usr.AlternativeSignInNamesInfo.First().Value = string.Format("{0}_{1}", usr.FirstName, usr.LastName);
usr.DisplayName = string.Format("{0} {1}", usr.FirstName, usr.LastName);
string json = Newtonsoft.Json.JsonConvert.SerializeObject(usr, Formatting.None);
Utils.GraphAPIHelper api = new Utils.GraphAPIHelper(graphAPIClientId, graphAPIClientSecret, tenant);
string res = await api.GraphPostRequest("/users/", json);
return RedirectToAction("Index");
}
catch (Exception e)
{
return View();
}
}
And in the GraphAPIHelper:
internal async Task<string> GraphPostRequest(string api, string json)
{
AuthenticationResult result = authContext.AcquireToken(graphResourceID, credential);
HttpClient http = new HttpClient();
string url = aadGraphEndpoint + tenant + api + "?" + aadGraphVersion;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
return await response.Content.ReadAsStringAsync();
}
And finally, some samplecode from the model, pls note JsonProperty(Order:
public class b2cuser
{
[JsonProperty(Order = 0, PropertyName = "accountEnabled")]
public bool AccountEnabled = true;
[JsonProperty(Order = 1, PropertyName = "alternativeSignInNamesInfo")]
public List<AlternativeSignInNamesInfo> AlternativeSignInNamesInfo { get; set; }
[JsonProperty(Order = 2, PropertyName = "creationType")]
public string CreationType = "NameCoexistence";

Getting Available Certificate uploaded on azure storage

I want to get all uploaded certificate on storage in azure to use these certificate associate with VM when I creating VM's using rest-api to.
Is it necessary, the certificate should available on local machine?
If yes, is there any way to install certificate locally, when the web site/ portal in open on any machine.
You need to install the certificate on each machine that uses REST api to be able to function.
The point of the private and public keys are to maintain security. I dont think this would be something you would want to put on a website for anyone to be able to install.
That being said, if you are making the REST call via a website, then only the server hosting the application needs to have the certificate installed.
I build a webrequest that has the REST URL in it, like this one, then build the response.
private HttpWebResponse CallAzure(HttpWebRequest request, string postData)
{
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certificateStore.Open(OpenFlags.ReadOnly);
var certs = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
if (request.Method.ToUpper() == "POST")
{
var xDoc = new XmlDocument();
xDoc.LoadXml(postData);
var requestStream = request.GetRequestStream();
var streamWriter = new StreamWriter(requestStream, Encoding.UTF8);
xDoc.Save(streamWriter);
streamWriter.Close();
requestStream.Close();
}
request.ClientCertificates.Add(certs[0]);
request.ContentType = "application/xml";
request.Headers.Add("x-ms-version", "2012-03-01");
ServicePointManager.Expect100Continue = false;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
request.ServicePoint.Expect100Continue = false;
var response = request.GetResponse();
return (HttpWebResponse)response;
}
I have found it easiest to install the certificate via PowerShell.
If you want to generate your own publishsettingfile here is a very easy app to do it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace CreatePublishSettingsFile
{
class Program
{
private static string subscriptionId = "[your subscription id]";
private static string subscriptionName = "My Awesome Subscription";
private static string certificateThumbprint = "[certificate thumbprint. the certificate must have private key]";
private static StoreLocation certificateStoreLocation = StoreLocation.CurrentUser;
private static StoreName certificateStoreName = StoreName.My;
private static string publishFileFormat = #"<?xml version=""1.0"" encoding=""utf-8""?>
<PublishData>
<PublishProfile
PublishMethod=""AzureServiceManagementAPI""
Url=""https://management.core.windows.net/""
ManagementCertificate=""{0}"">
<Subscription
Id=""{1}""
Name=""{2}"" />
</PublishProfile>
</PublishData>";
static void Main(string[] args)
{
X509Store certificateStore = new X509Store(certificateStoreName, certificateStoreLocation);
certificateStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = certificateStore.Certificates;
var matchingCertificates = certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);
if (matchingCertificates.Count == 0)
{
Console.WriteLine("No matching certificate found. Please ensure that proper values are specified for Certificate Store Name, Location and Thumbprint");
}
else
{
var certificate = matchingCertificates[0];
certificateData = Convert.ToBase64String(certificate.Export(X509ContentType.Pkcs12, string.Empty));
if (string.IsNullOrWhiteSpace(subscriptionName))
{
subscriptionName = subscriptionId;
}
string publishSettingsFileData = string.Format(publishFileFormat, certificateData, subscriptionId, subscriptionName);
string fileName = Path.GetTempPath() + subscriptionId + ".publishsettings";
File.WriteAllBytes(fileName, Encoding.UTF8.GetBytes(publishSettingsFileData));
Console.WriteLine("Publish settings file written successfully at: " + fileName);
}
Console.WriteLine("Press any key to terminate the program.");
Console.ReadLine();
}
}
}

Resources