I am no longer able to debug/run my SharePoint Remote Event Receiver locally using Ngrok - sharepoint

Last month the below steps were working well for me to debug and test a SharePoint online remote event receiver locally:-
Open Ngrok.exe >> run the following command inside ngrok:-
ngrok authtoken 3***e
ngrok http --host-header=rewrite 57269
register a new app:- # https://.sharepoint.com/sites//_layouts/15/AppRegNew.aspx >> enter the above Ngrok urls inside the App Redirect URL & App Domain.
Inside the _layouts/15/appinv.aspx >> I search for the above app using Client ID >> and enter the following:-
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
Update the service's web config with the above ClientID and ClientSecret
Register the new remove event receiver as follow:-
Add-PnPEventReceiver -List "Order Management" -Name "TasksRER" -Url http://cc6e945e82f6.ngrok.io/service1.svc -EventReceiverType ItemUpdated -Synchronization Asynchronous
But today when I tried the above steps it failed >> where inside my event receiver when I tried to get the SharePoint context >> I will get that the Context is null:-
public void ProcessOneWayEvent(SPRemoteEventProperties properties)
{
var prop = properties;
var listItemID = properties.ItemEventProperties.ListItemId;
var listTitle = properties.ItemEventProperties.ListTitle;
using (ClientContext context = Helpers.GetAppOnlyContext(properties.ItemEventProperties.WebUrl))
{
context.Load(context.Web);
context.ExecuteQuery();
Here is a screen shot from Visual Studio with the error i am getting when trying to get the context:-
Any advice if anything has been changed which is preventing me from running the above steps? which were working well last month?
Thanks
here is the code for the GetAppOnlyContext
public class Helpers
{
public static ClientContext GetAppOnlyContext(string siteUrl)
{
try
{
Uri siteUri = new Uri(siteUrl);
string realm = TokenHelper.GetRealmFromTargetUrl(siteUri);
string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUri.Authority, realm).AccessToken;
return TokenHelper.GetClientContextWithAccessToken(siteUri.ToString(), accessToken);
}
catch (Exception ex)
{
Trace.TraceInformation("GetAppOnlyContext failed. {0}", ex.Message);
}
return null;
}
public static ClientContext GetAuthenticatedContext(string siteUrl)
{
string userName = WebConfigurationManager.AppSettings.Get("AuthenticatedUserName");
string password = WebConfigurationManager.AppSettings.Get("AuthenticatedUserPassword");
return GetAuthenticatedContext(siteUrl, userName, password);
}
public static ClientContext GetAuthenticatedContext(string siteUrl, string userName, SecureString password)
{
ClientContext ctx = new ClientContext(siteUrl);
ctx.Credentials = new SharePointOnlineCredentials(userName, password);
return ctx;
}
public static ClientContext GetAuthenticatedContext(string siteUrl, string userName, string password)
{
SecureString securePassword = GetPassword(password);
return GetAuthenticatedContext(siteUrl, userName, securePassword);
}
private static SecureString GetPassword(string passwd)
{
var secure = new SecureString();
foreach (char c in passwd)
{
secure.AppendChar(c);
}
return secure;
}
public static string EmptyIfNull(object obj)
{
return obj == null ? "" : obj.ToString();
}
}
}

Related

Issue related to fetching certificate from Azure Keyvault using Java

I am migrating our legacy application into Azure Cloud . In the existing application we are securing our Jetty Server while starting so for that we are using jks file to secure our Jetty server .
Now we are moving into Azure Cloud so we have to fetch the .jks file from Azure keyvault . So how to fetch the complete .jks file from Azure keyvault . I am able to fetch the secrets from Keyvault but unable to fetch the certificate (which i uploaded in Azure keyvault). I am not sure whether we have any API which gives the certificate file.
Below code i am using to fetch the secrets & certificates:
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
import com.microsoft.azure.keyvault.models.CertificateBundle;
import com.microsoft.azure.keyvault.models.SecretBundle;
public class DemoTest {
private static String vaultBase = "https://abc.vault.azure.net/";
private static String ClientId = "*******************";
private static String clientKey = "*****************";
public static void main(String[] args) {
KeyVaultClient keyVaultClient = GetKeyVaultClient();
SecretBundle getSecret=keyVaultClient.getSecret(vaultBase, "mysecretkey");
SecretBundle getSecret1=keyVaultClient.getSecret(vaultBase, "DB-PASSWORD-POC");
SecretBundle getSecret2=keyVaultClient.getSecret(vaultBase, "certificate-value");
// SecretBundle getSecret2=keyVaultClient.getSecret(vaultBase, "DB-PASSWORD-DEV");
CertificateBundle getCertificate=keyVaultClient.getCertificate(vaultBase, "abcprod");
CertificateBundle bundle = keyVaultClient.getCertificate("https://abc.vault.azure.net/certificates/abcprod/********386c9403bab8337ce21d27495");
System.out.println(getSecret.value());
System.out.println(getSecret1.value());
System.out.println(getSecret2.value());
// System.out.println(getCertificate.contentType());
// System.out.println(getCertificate.id());
// System.out.println(getCertificate.kid());
// System.out.println(getCertificate.toString());
// System.out.println(getCertificate.attributes().toString());
// System.out.println(getCertificate.keyIdentifier().name());
// System.out.println(getCertificate.sid());
// System.out.println(getCertificate.certificateIdentifier().baseIdentifier());
// System.out.println(bundle.cer());
// System.out.println(bundle);
}
private static KeyVaultClient GetKeyVaultClient() {
return new KeyVaultClient(new KeyVaultCredentials() {
#Override
public String doAuthenticate(String authorization, String resource, String scope) {
String token = null;
try {
AuthenticationResult authResult = getAccessToken(authorization, resource);
token = authResult.getAccessToken();
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
});
}
public static AuthenticationResult getAccessToken(String authorization, String resource) throws InterruptedException, ExecutionException, MalformedURLException {
AuthenticationResult result = null;
//Starts a service to fetch access token.
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
AuthenticationContext context = new AuthenticationContext(authorization, false, service);
Future<AuthenticationResult> future = null;
//Acquires token based on client ID and client secret.
if (ClientId != null && clientKey != null) {
ClientCredential credentials = new ClientCredential(ClientId, clientKey);
future = context.acquireToken(resource, credentials, null);
}
result = future.get();
} finally {
service.shutdown();
}
if (result == null) {
throw new RuntimeException("Authentication results were null.");
}
return result;
}
}
We are securing our jetty server with this code :
public class ABCSubscriber {
private static final int Port = 9090;
private static final String KeyStoreType = "jks";
private static final String KeyStoreFile = "/home/abc/xyz/subscriber.jks";
private static final String KeyStorePassword = "******";
private static final String KeyPassword = "*******";
private static final String ContextPath = "/";
private static final String URLPattern = "/*";
public static void main(String[] args) throws Exception {
Server server = new Server();
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(Port);
http_config.setRequestHeaderSize(8192);
// HTTP connector
ServerConnector http = new ServerConnector(server,
new HttpConnectionFactory(http_config));
http.setPort(9091);
http.setIdleTimeout(30000);
// SSL Context Factory
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreType(KeyStoreType);
sslContextFactory.setKeyStorePath(KeyStoreFile);
sslContextFactory.setKeyStorePassword(KeyStorePassword);
sslContextFactory.setKeyManagerPassword(KeyPassword);
// sslContextFactory.setTrustStorePath(ncm.getKSFile());
// sslContextFactory.setTrustStorePassword("changeit");
sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
sslConnector.setPort(Port);
server.addConnector(sslConnector);
/**Disable and enable protocols*/
String[] includeProtocols = {"TLSv1.1","TLSv1.2"};
sslContextFactory.addExcludeProtocols("TLSv1.0");
sslContextFactory.setIncludeProtocols(includeProtocols);
/**End Disable and enable protocols*/
// HTTPS Configuration
ServerConnector https = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
https.setPort(Port);
https.setIdleTimeout(30000);
//server.setConnectors(new Connector[] { http, https });
server.setConnectors(new Connector[] { https });
ServletContextHandler ctxt = new ServletContextHandler(0);
ctxt.setContextPath(ContextPath);
server.setHandler(ctxt);
ctxt.addServlet(new ServletHolder(new ABCServlet()), "/*");
try {
server.start();
} catch ( Exception e ) {
e.getLocalizedMessage();
};
server.join();
}
}
So , Is there any way to get the certificate file from Azure keyvault? If not then how can we use certificate to secure the server ?
Can anyone please help me on this ?
Thanks in Advance !!!
You need to download the private key of the certificate as a secret. Getting the secret using the more obvious GetCertificate will only return the public key part of the certificate.
I know this is C# in the code example below, but that is how I get the certificate out of Key Vault, I hope you can get an idea on how to do the same in Java:
/// <summary>
/// Helper method to get a certificate
///
/// Source https://github.com/heaths/azsdk-sample-getcert/blob/master/Program.cs
/// </summary>
/// <param name="certificateClient"></param>
/// <param name="secretClient"></param>
/// <param name="certificateName"></param>
/// <returns></returns>
private static X509Certificate2 GetCertificateAsync(CertificateClient certificateClient,
SecretClient secretClient,
string certificateName)
{
KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificate(certificateName);
// Return a certificate with only the public key if the private key is not exportable.
if (certificate.Policy?.Exportable != true)
{
return new X509Certificate2(certificate.Cer);
}
// Parse the secret ID and version to retrieve the private key.
string[] segments = certificate.SecretId.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (segments.Length != 3)
{
throw new InvalidOperationException($"Number of segments is incorrect: {segments.Length}, URI: {certificate.SecretId}");
}
string secretName = segments[1];
string secretVersion = segments[2];
KeyVaultSecret secret = secretClient.GetSecret(secretName, secretVersion);
// For PEM, you'll need to extract the base64-encoded message body.
// .NET 5.0 preview introduces the System.Security.Cryptography.PemEncoding class to make this easier.
if ("application/x-pkcs12".Equals(secret.Properties.ContentType, StringComparison.InvariantCultureIgnoreCase))
{
byte[] pfx = Convert.FromBase64String(secret.Value);
return new X509Certificate2(pfx);
}
throw new NotSupportedException($"Only PKCS#12 is supported. Found Content-Type: {secret.Properties.ContentType}");
}
}
}
Here is the Java code equivalent to answer posted by #Tore Nestenius
public byte[] getPkcsFromAzureKeyVault(String certificateName) throws InvalidDataException {
String keyVaultName = System.getenv("KEY_VAULT_NAME");
String keyVaultUri = "https://" + keyVaultName + ".vault.azure.net";
CertificateClient certificateClient = new CertificateClientBuilder().vaultUrl(keyVaultUri)
.credential(new DefaultAzureCredentialBuilder().build()).buildClient();
KeyVaultCertificateWithPolicy certPol = certificateClient.getCertificate(certificateName);
SecretClient secretClient = new SecretClientBuilder().vaultUrl(keyVaultUri)
.credential(new DefaultAzureCredentialBuilder().build()).buildClient();
KeyVaultSecret secret = secretClient.getSecret(certPol.getProperties().getName(),
certPol.getProperties().getVersion());
if ("application/x-pkcs12".equalsIgnoreCase(secret.getProperties().getContentType())) {
return Base64.getDecoder().decode(secret.getValue());
}
throw new InvalidDataException();
}

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}"}

mvc azure ad token expiration

I'm currently building a mvc5 app hosted on azure which will be in term used throught a WPF app.
As I need to check user group membership I implemented graph API by following the guidance in this article : https://azure.microsoft.com/fr-fr/documentation/samples/active-directory-dotnet-graphapi-web/
It works quite fine but some time after the user logged in the access to the following controller raise an access denied error :
public async Task<ActionResult> Index()
{
string uID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IUser adUser = client.Users.Where(u => u.ObjectId == uID).ExecuteAsync().Result.CurrentPage.SingleOrDefault();
IList<Group> groupMembership = new List<Group>();
var userFetcher = (IUserFetcher)adUser;
IPagedCollection<IDirectoryObject> pagedCollection = await userFetcher.MemberOf.ExecuteAsync();
do
{
List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
foreach (IDirectoryObject directoryObject in directoryObjects)
{
if (directoryObject is Group)
{
var group = directoryObject as Group;
groupMembership.Add(group);
}
}
pagedCollection = await pagedCollection.GetNextPageAsync();
} while (pagedCollection != null);
ViewBag.User = adUser.UserPrincipalName;
ViewBag.UserDN = adUser.DisplayName;
ViewBag.UserGN = adUser.GivenName;
ViewBag.UserMail = adUser.Mail;
ViewBag.UserSN = adUser.Surname;
return View(groupMembership);
}
The exception is raised on GetActiveDirectoryClient(), the code of this method is a strict copy/paste from the article in the link and looks like this :
internal class AuthenticationHelper
{
public static string token;
/// <summary>
/// Async task to acquire token for Application.
/// </summary>
/// <returns>Async Token for application.</returns>
public static async Task<string> AcquireTokenAsync()
{
if (token == null || token.IsEmpty())
{
throw new Exception("Authorization Required. ");
}
return token;
}
/// <summary>
/// Get Active Directory Client for Application.
/// </summary>
/// <returns>ActiveDirectoryClient for Application.</returns>
public static ActiveDirectoryClient GetActiveDirectoryClient()
{
Uri baseServiceUri = new Uri(Constants.ResourceUrl);
ActiveDirectoryClient activeDirectoryClient =
new ActiveDirectoryClient(new Uri(baseServiceUri, Constants.TenantId), async () => await AcquireTokenAsync());
return activeDirectoryClient;
}
}
This code works perfectly right after the user has logged in but after some times the token become null and so the exception is raised.
I'm guessing this is related to some expiration time, so is there's a way to set some auto refresh on the token ?
Thanks !
Thanks for answering, I don't have yet set the [Authorize] tag as I would like to as Azure AD group membership to grant access to controllers and haven't yet figured out how to achieve it :)
It seems that appliying mofifications to the authenticationHelper solved the issue :
public static ActiveDirectoryClient GetActiveDirectoryClient()
{
Uri baseServiceUri = new Uri(Constants.ResourceUrl);
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
ClientCredential credential = new ClientCredential(clientId, appKey);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(new Uri(baseServiceUri, Constants.TenantId), async () =>
{
var result = await authContext.AcquireTokenSilentAsync(graphUrl, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return result.AccessToken;
});
return activeDirectoryClient;
}
I don't know if that's a clean way to do thing it at least it works.

How can we create or list the Tags to Azure Virtual Machine in .Net SDK

I want to list and change the tags and their values for the Azure Virtual Machines using .NET SDK.
Please let me know the way for this.
Thank You.
Since I don't have a Virtual Machine handy, I am posting code for updating tags for a Resource Group.
First, please ensure that Azure AD application is properly set up. You may find this link useful for that purpose: https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx.
Next, I created a simple console application. What you would need to do is get Microsoft.Azure.ResourceManager 1.0.0-preview and Active Directory Authentication Library 2.22.302111727 Nuget packages in your application.
After that, things are pretty simple. Please see the code below:
using System;
using System.Linq;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading;
using Microsoft.Azure.Management.Resources;
using Microsoft.Rest;
namespace AzureARMDemo
{
class Program
{
private static string ClientId = "<your-application-client-id>";//This is the PowerShell Client Id
private static string TenantId = "<tenant-id>";
private static string LoginEndpoint = "https://login.microsoftonline.com/";
private static string ServiceManagementApiEndpoint = "https://management.core.windows.net/";
private static string RedirectUri = "urn:ietf:wg:oauth:2.0:oob";
private static string SubscriptionId = "<your-azure-subscription-id>";
private static string AzureResourceManagerEndpoint = "https://management.windows.net";
private static string ResourceGroupNameToUpdate = "<resource-group-name-to-update>";
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
var credentials = new TokenCredentials(token);
var resourceManagerClient = new ResourceManagementClient(new Uri(AzureResourceManagerEndpoint), credentials)
{
SubscriptionId = SubscriptionId,
};
Console.WriteLine("Listing resource groups. Please wait....");
Console.WriteLine("----------------------------------------");
var resourceGroup = resourceManagerClient.ResourceGroups.List().FirstOrDefault(r => r.Name == ResourceGroupNameToUpdate);
if (resourceGroup != null)
{
var tags = resourceGroup.Tags;
if (!tags.ContainsKey("Key1"))
{
tags.Add("Key1", "Value1");
}
else
{
tags["Key1"] = tags["Key1"] + " Updated";
}
Console.WriteLine("Updating resource group. Please wait....");
Console.WriteLine("----------------------------------------");
resourceManagerClient.ResourceGroups.Patch(ResourceGroupNameToUpdate, resourceGroup);
Console.WriteLine("Resource group updated.");
Console.WriteLine("-----------------------");
}
//var resourceGroups = resourceManagerClient.ResourceGroups.List();
//foreach (resourceGroup in resourceGroups)
//{
// Console.WriteLine("Resource Group Name: " + resourceGroup.Name);
// Console.WriteLine("Resource Group Id: " + resourceGroup.Id);
// Console.WriteLine("Resource Group Location: " + resourceGroup.Location);
// Console.WriteLine("----------------------------------------");
//}
Console.WriteLine("Press any key to terminate the application");
Console.ReadLine();
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext(LoginEndpoint + TenantId);
var thread = new Thread(() =>
{
result = context.AcquireToken(
ServiceManagementApiEndpoint,
ClientId,
new Uri(RedirectUri));
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
}
}

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";

Resources