Getting Azure Active directory token - c#

I have an Azure Account, now I'm trying to get token in an console application to manage resources (i.e. create a resource group etc):
string userName = "xyz#gmail.com";
string password = "XXXXXXXXX";
string directoryName = "xyzgmail.onmicrosoft.com";
string clientId = "guid-of-registered-application-xxx";
var credentials = new UserPasswordCredential(userName, password);
var authenticationContext = new AuthenticationContext("https://login.windows.net/" + directoryName);
var result = await authenticationContext.AcquireTokenAsync("https://management.core.windows.net/", clientId, credentials);
On AcquireTokenAsync call I have
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException:
'accessing_ws_metadata_exchange_failed: Accessing WS metadata exchange
failed'
Can anybody help, please?
Update: how I tried to create a resource group under newly created user
var jwtToken = result.AccessToken;
string subscriptionId = "XX-XX-XX-YY-YY-YY";
var tokenCredentials = new TokenCredentials(jwtToken);
var client = new ResourceManagementClient(tokenCredentials);
client.SubscriptionId = subscriptionId;
var rgResponse = await client.ResourceGroups.CreateOrUpdateWithHttpMessagesAsync("myresgroup77777",
new ResourceGroup("East US"));
Here I got another exception
'The client 'newaduser#xyzgmail.onmicrosoft.com' with object id
'aaa-aaa-aaa-aaa' does not have authorization to perform action
'Microsoft.Resources/subscriptions/resourcegroups/write' over scope
'/subscriptions/XX-XX-XX-YY-YY-YY/resourcegroups/myresgroup77777'.'

Not sure why you're getting the first error, but the second error is because the signed in user does not have permission to perform the operation (as mentioned in the error message).
When you assign the permission to execute Windows Azure Service Management API, it is actually assigned to the application which assumes the identity of the signed in user.
In order to perform Create Resource Group operation in Azure Subscription, that user must be in a role that allows this operation to be performed. You can try by assigning built-in Contributor role at the Azure Subscription level to this user.
Also, regarding using login.windows.net v/s login.microsoftonline.com, it is recommended that you use latter. When you use login.windows.net, it gets automatically redirected to login.microsoftonline.com. Using login.microsoftonline.com will save you one redirection.

Related

Azure C# KeyVaultErrorException: Operation returned an invalid status code 'Forbidden'

I am writing a program that tries to access a secret (OneAuthZAuthentication) to an Azure Table Storage through accessing KeyVault. I am following the steps listed in this tutorial: https://jeanpaul.cloud/2019/12/07/azure-key-vault-access-from-c/
I have created a Key Vault called ITALocalBuildSecrets:
With the following DNS Name: https://italocalbuildsecrets.vault.azure.net/
I also have another secret with the following name (OneAuthZAuthentication):
I have created an app in the active directory (OneAuthZUserApplication), and you can see the Application (client) ID displayed below:
I created a client secret for OneAuthZUserApplication:
I authorized a Console Application (OneAuthZUserApplication) as an access policy:
And you can clearly see the access policy being registered:
Below is the code I am running:
// Retrieves the access token necessary to gain authentication into the key vault
[FunctionName("GetToken")]
public static async System.Threading.Tasks.Task<string> GetToken(string authority, string resource, string scope)
{
var clientId = "5cf497b0-3467-456a-a03a-4d4414b*****"; // Stars are for security reasons :D
var clientSecret = "468.26i5Wc.nQ6TYL-eOvBmcto.t.*****"; // Stars are for security reasons
ClientCredential credential = new ClientCredential(clientId, clientSecret);
var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
var result = await context.AcquireTokenAsync(resource, credential);
return result.AccessToken;
}
// Retrieves the access key vault accountKey (needed to authenticate access into the role assignments table)
public static string GetVaultValue()
{
KeyVaultClient client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var vaultAddress = "https://italocalbuildsecrets.vault.azure.net/";
var secretName = "OneAuthZAuthentication";
var secret = client.GetSecretAsync(vaultAddress, secretName).GetAwaiter().GetResult();
return secret.Value;
}
[FunctionName("Function1")]
// Function that reads a small portion of the role assignments table (OneAuthZRoleAssignments) every
// configurable number of times
public static async System.Threading.Tasks.Task RunAsync([TimerTrigger("%TimerTriggerPeriod%")]TimerInfo myTimer, ILogger log)
{
Console.WriteLine($"Secret Value from Vault is: {GetVaultValue()}");
}
I get the following error:
Function1. Microsoft.Azure.KeyVault: Operation returned an invalid status code 'Forbidden'.
This does seems strange, considering that I authorized the OneAuthZUserApplication application to the key vault.
I follow you steps and use your code to test, and it all works very well.
Please go to confirm after adding Access policy, remember to click save button.
What is the authority you are using? Further, I think you are missing the step of configuring scopes when getting the token. Similar here, but using MSAL.
string[] scopeArray = new string[] { "https://vault.azure.net/.default" };
And provide that to your token request.
Also, if these are Azure Functions, why don't you use the function MSI to retrieve the secret? See here

AADSTS501051: Application '{API GUID}'(DEV-API) is not assigned to a role for the application '{API GUID}'(DEV-API)

I want to access one API by its Client Credential directly not via any web application
private async Task<string> GetAutheticationToken(string APITypeSelected, string APIKeySelected=null)
{
string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
string tenant = ConfigurationManager.AppSettings["ida:AADTenant"];
string appKey = ConfigurationManager.AppSettings[APIKeySelected];
string apiID = ConfigurationManager.AppSettings[APITypeSelected];
//appKey = HttpUtility.UrlEncode(appKey);
string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
using (HttpClient client = new HttpClient())
{
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext authContext = null;
ClientCredential clientCredential = null;
authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
//encodeURIComponent(client_secret);
clientCredential = new ClientCredential(apiID, appKey);
AuthenticationResult authResult = null;
authResult = await authContext.AcquireTokenAsync(apiID, clientCredential);
return authResult.AccessToken;
}
}
while executing I am getting bellow error(AADSTS501051) in this line
authResult = await authContext.AcquireTokenAsync(apiID, clientCredential);
AADSTS501051: Application '{API GUID}'(DEV-API) is not assigned to a
role for the application '{API GUID}'(DEV-API).
Do I have to give API permission to itself.
What I need to do.
Thanks,
First you need to make a user role for application if app assignment is required. if not there is no problem. If app assignment is required, Go back to api permission and in my api give permission for the created role, see Microsoft documentation url
https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-app-registration
Ahh so you want an access token to the API itself? Not sure if that's possible..
If this in another app, it should be registered as another app in Azure AD.
It can then require application permissions on the API and call it via client credentials.
You can see how to define permissions here: https://joonasw.net/view/defining-permissions-and-roles-in-aad
If this is within the same app, it sounds odd that it would acquire a token for itself.
This error message indicates that you need to add an "App role" to your app registration. You can do so by first adding a new App role on {API GUID}
and then assign the app {API GUID} this role (don't forget to give admin consent)
Essentially what is happening here is that your app registration {API GUID} got a role on {API GUID} to create access tokens for the audience {API GUID}, so: itself.
When you use "authContext.AcquireTokenAsync(apiID, clientCredential);" to get the access token, you need to use identifierUri of your ad application as resource.
For example:
string tenantId = "your tenant id or name, for example: hanxia.onmicrosoft.com";
string clientId = "your client id";
string resource = "the identifierUri of your ad application ";
string clientSecret = "";
ClientCredentia clientCredentia = new ClientCredentia(clientId,clientSecret);
var context = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId);
AuthenticationResult result = context.AcquireTokenAsync(resource, clientCredentia);
For more details, please refer to the document.

Fetch user details from Azure AD

I am trying to fetch users' details from Azure AD using Graph API.
My code is like this :
public B2CGraphClient(string clientId, string clientSecret, string tenant)
{
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tenant = tenant;
this.authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
this.credential = new ClientCredential(clientId, clientSecret);
}
public string GetUserByObjectId(string objectId)
{
return SendGraphGetRequest("/users/" + objectId);
}
public string SendGraphGetRequest(string api)
{
AuthenticationResult result = authContext.AcquireToken("https://graph.windows.net", credential);
HttpClient http = new HttpClient();
string url = "https://graph.windows.net/" + tenant + api + "?" + "api-version=1.6";
}
But i am gettign an exception at AcquireToken line in SendGraphGetRequest method as -
Error validating credentials. Invalid client secret is provided
Inner Exception is :{"The remote server returned an error: (401) Unauthorized."}
I have provided both - Client ID and Client secret Key, But still getting this exception.
What am I missing here?
Based on the error message, the secret is incorrect. You can regenerate a new secret on Azure portal and use the new secret to fix this issue.
If you're sure that the secret is correct, then make sure that the Application you've registered to use as the service principal has been assigned rights:
This particular permission requires that you get approval from an AAD administrator before access is granted.
From the AAD Documentation:
Request the permissions from a directory admin
When you're ready to request permissions from the organization's admin, you can redirect the user to the v2.0 admin consent endpoint.
// Line breaks are for legibility only.
GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
// Pro tip: Try pasting the following request in a browser!
https://login.microsoftonline.com/common/adminconsent?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&state=12345&redirect_uri=http://localhost/myapp/permissions

AzureAD multiteenant app - "Authorization_RequestDenied": "Insufficient privileges to complete the operation

I am referring to Multitenant-saas-app sample. I am trying to get an access token to access Graph API and then get access token silently and access the graph api again.
Get Authorisation Code with /common endpoint for the multi-tenant-app,
private string resourceID = "https://graph.windows.net";
string authorizationRequest = String.Format(
"https://login.microsoftonline.com/common/oauth2/authorize?response_type=code&client_id={0}&resource={1}&redirect_uri={2}&state={3}",
Uri.EscapeDataString(ConfigurationManager.AppSettings["ida:ClientID"]),
Uri.EscapeDataString("https://graph.windows.net"),
Uri.EscapeDataString(this.Request.Url.GetLeftPart(UriPartial.Authority).ToString() + "/Onboarding/ProcessCode"),
Uri.EscapeDataString(stateMarker)
);
return new RedirectResult(authorizationRequest);
Redirected with authorisation code, (/Onboarding/ProcessCode)
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
ConfigurationManager.AppSettings["ida:Password"]);
AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common/");
//Get token to access grapgh API
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
code, new Uri(Request.Url.GetLeftPart(UriPartial.Path)), credential, resourceID);
AuthenticationHelper.token = result.AccessToken;
This works fine and I get the access token where I can access the AzureAD resources for the tenant.
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IPagedCollection<IUser> pagedCollection = await client.Users.ExecuteAsync();
Now I try to get get the token for offline access from the token cache. This time I create AuthenticationContext for the tenant. (I tried /common as well)
This gets me a new accesstoken silently.
string resourceID = "https://graph.windows.net";
//Test
ClientCredential credential = new ClientCredential(ConfigurationManager.AppSettings["ida:ClientID"],
ConfigurationManager.AppSettings["ida:Password"]);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/mytenant.net");
var auth = await authContext.AcquireTokenAsync(resourceID, credential);
var newToken = auth.AccessToken;
//Set the token for this session
AuthenticationHelper.token = auth.AccessToken;
Then I try to access the API as previous,
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IPagedCollection<IUser> pagedCollection = await client.Users.ExecuteAsync();
and I get the following exception,
Error = "Authorization_RequestDenied": "Insufficient privileges to
complete the operation."
Am I doing anything wrong here?
Here is my app permissions,
To list the users using the Azure AD graph REST, we require the Read all users' basic profile or Read all users' full profiles if you were not a global admin in the tenant.
And if you were the Global Admin in the tenant, the Access the directory as the sign-in user should also work to list users rest API.
And more detail about the scopes about Azure AD graph, you can refer here.
And for the cache issue, since you didn't provide custom cache, it would use the default cache based on the platform. For example, if you were developing an .Net application, the cache is using the memory to store the object. So it only works before you restart the application.

How to create record in CRM by Azure AD authentication?

I create a Native client application. I have got access token result from Azure AD by the article given below:
https://msdn.microsoft.com/en-us/library/dn531009.aspx
code give below:
Uri serviceUrl = new System.Uri(CrmServiceUrl + "/XRMServices/2011/Organization.svc/web");
string _oauthUrl = "https://login.windows.net/00000000-0000-0000-0000-000000000000/oauth2/authorize"; // DiscoveryAuthority
String resource = "https://****.crm.dynamics.com/";
authenticationContext = new AuthenticationContext(_oauthUrl, false);
//custom test code
AuthenticationResult result = authenticationContext.AcquireToken(resource, _clientID, serviceUrl, PromptBehavior.Auto);
return result.AccessToken;
now my question is this, How i can create service proxy from that "Access token" to make CRUD operations?
is it possible to create record in dynamic crm using access token or not?
your response should be appreciated.
thanks.

Categories