Getting "an error occurred while sending the request" while trying to create an application registration on Azure programmatically - azure

I have a use case for a project where I need to automate the creation of Application Registration on Azure programmatically.
I have been using this sample. for doing so.
I am also following the documentation from microsoft on creating an application.
I have done the same in my code snippet as shown in the image below and also added the functionality to add a password to the created Application.
This process used to work before where in the Application used to get registered and the flow was as expected.
However now when I try running this request, I get an error saying "Error occurred while sending the request". There does not seem to be any documentation related to error codes related to this.
Can you help me find the relevant material or changes that have been made my microsoft on graph client that may be causing this?
Update
As per comments I found the IDs of the needed API Permissions using Powershell.
I added them to my code as well as follows
The Permissions added are Application.ReadWrite.All and Application.ReadWrite.OwnedBy respectively as Type role. I still get the same error.
The inner exception is as follows:

Summarize from the comments:
The problem was caused by permissions. We should add the required permissions(add at least one of the two permissions Application.ReadWrite.All, Directory.AccessAsUser.All in Delegated type) to the registered app "API permissions" tab and then just use https://graph.microsoft.com/.default as scope in code.
By the way, if want to add the permissions by their id, we can get the permissions and ids by request this url: https://graph.microsoft.com/v1.0/serviceprincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'
================================Update===========================
First you need to have a registered app in your Azure AD. Here I have an app named "huryGetToken4". If you do not have the app, you can refer to this document to register the app. Go to your registered app and click "API permissions" tab. Add the permissions which are required.
Please do not forget do "Grand admin consent for xxx" after add the permissions.
Then click "Certificates & secrets" tab and new a client secret. Copy the secret to your notepad.
Then we can develop the code, below is my code for your reference:
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System;
namespace ConsoleApp7
{
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
Console.WriteLine("Hello World!");
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("clientId")
.WithTenantId("tenantId")
.WithClientSecret("clientSecret")
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var application = new Application
{
DisplayName = "huryNewApp1"
};
await graphClient.Applications.Request().AddAsync(application);
}
}
}
For the clientId and tenantId in my code, you can find them on the "Overview" page of your registered app.
After running the code, the new app will be created in Azure AD.

Related

Setting up an Application with Azure for use with Graph API outlook calendars

I'm aware that Graph API has a nice nuget package and I am confident on the code side of things, but my understanding is that I need to have the application set up in Azure and while there is a lot of documentation about this in general, I find it quite dense and I'm not confident I have the specifics down for how I need to set this portion up.
What I need my application to do is access an outlook calendar of a specific user that I own, read, search, add, delete and update calendar items. The integration assistant seems to suggest I need to configure a URI redirect and configure api permission. The default persmission is User.Read on graph API and if I try to add a permission, office 365 management seems like it might be the one I need except it specifically says just retrieving user information and nothing mentions outlook anywhere.
I need to know more or less the minimum steps in setting up the application in Azure to write a C# application that can make changes to outlook for a user.
need my application to do is access an outlook calendar of a specific user
Does it mean you need your app to have the abiltity to modify the callendar of any user you owned? If not, then it means you need your application to provide a sign in module and let users sign in, then the users can get authentication to call graph api and manage their own calendar, since this scenario, users give the delegate api permission, so they can't manage other users' calendar, so I don't think this is what you want.
If so, then you should use client credential flow to generate access token to call graph api. I think you know that when you want to call graph api, you have to get an access token which has correct permission first.
Ok, then let's come to the api permission, when you go to api document of the Calendar. You will see permissions like screenshot below:
Application permission type is suitable for client credential flow. And after viewing all the apis, you will find that they all need Calendars.ReadWrite except those not supporting Application type.
Then let's go to azure portal and reach Azure Active Directory. You need to create an Azure ad application and give the app Calendars.ReadWrite permission, then give the Admin consent.
Then you also need to create a client secret, pls go to Certificates & Secrets and add a new client secret, don't forget to copy the secret after you create it.
Now you've done all the steps. No need to set a redirect url, because you don't need to let the user to sign in your application. Let's see client credential flow document, it only require client_id, client_secret to generate access token.
Or in the code, you may use SDK like this :
using Azure.Identity;
using Microsoft.Graph;
public async Task<IActionResult> Index()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var calendar = new Calendar{ Name = "Volunteer" };
var events = await graphClient.Users["user_id_which_is_needed_to_list_calendar_events"].Events.Request()
.Header("Prefer","outlook.timezone=\"Pacific Standard Time\"")
.Select("subject,body,bodyPreview,organizer,attendees,start,end,location")
.GetAsync();
return View();
}

Unable to get access token. 'AADSTS500011: The resource principal named 'xxx' was not found in the tenant -tenantid

I am trying to get the access token for the Azure function app. I have enabled managed identity for the function app(system assigned). but while fetching the token using the nuget Azure.Identity.
var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { "https://xxx.azure-api.net/" + "/.default" }) { }
);
I am getting the error.
The resource principal named 'xxx.azure-api.net' was not found in
the tenant 123
but when run az cli to check the subscription details, the subscription indeed part of the tenant 123 only.
Here is what I have finally done.
I have registered an App in AD. and Exposed the API of that App.
I have assigned System Assigned Managed Identity to the Function.
In the local I am not able to request token because Azure CLI is not given consent.
After deploying the application in Function my Function app can request a token using its identity.
You need to register the application in azure ad and enable the access token. Once that is done the you need to provide RBAC access to your xxx.azurewebsites.net
Follow this article for the step by step documentation Microsoft Document Reference
Unfortunately, the error message is not really helpful. But adding a scope to the app registration solved the problem for me:
In Azure Portal navigate to App Registrations
Find your app, in the left side menu select Manage => Expose an API
Add a scope. I named mine api_access as this was where this error occurred.
In my case I then got an API URI (like api://client-id/scope_name) which I used in my Angular app. Error message was gone.
Also, make sure that in the Enterprise Application you have created, under Manage => Properties, "Assignment required" and "Visible to users" is turned on.

Azure Service Bus managed identity in Visual Studio returning 401 - Token issuer is invalid

I'm attempting to access Azure Service Bus using a managed identity from my code. At the moment I'm just trying this locally.
When I debug my code I get the following error
System.UnauthorizedAccessException: Put token failed. status-code: 401, status-description: InvalidIssuer: Token issuer is invalid
Here is my service bus instance
Here is my user with Azure Service Bus Data Owner permissions
And here is my code
_client = new ServiceBusClient("oconnorevents.servicebus.windows.net", new DefaultAzureCredential());
I am logged into Visual Studio as the same user added to the service bus. I also tried logging in via the CLI but it didn't help.
Where am I going wrong here?
I've looked at this similar recent question here but the solutions proposed didn't work for me.
Since I have access to several different tenants, Visual Studio sometimes gets confused. Another way you can handle this is to continue to use the DefaultAzureCredential, but to give Visual Studio a hint about which tenant to use.
First left click the your project and examine the properties and then:
Left-click "Debug"
Left-click the "Add" button to add an environment variable
For name use "AZURE_TENANT_ID" and for value use your tenant id. Yes, that is a bogus tenant id in the picture :-)
Reference
https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet
https://damienbod.com/2020/10/09/using-key-vault-certificates-with-microsoft-identity-web-and-asp-net-core-applications/
If you use DefaultAzureCredential to auth, it will try several credential types to auth as mentioned here, one of them is VisualStudioCredential, but it will auth to the home AAD tenant of the user logged in VS, in your case, I suppose the service bus is in a subscription which is not under the home tenant of the user.
I can also reproduce your issue on my side.
To solve the issue, just use VisualStudioCredential directly, then simply specify the TenantId via VisualStudioCredentialOptions, then it will work fine.
Sample:
To find the TenantId, just navigate to the Azure Active Directory which the subscription of your service bus located.
TokenCredential tokenCredential = new VisualStudioCredential(new VisualStudioCredentialOptions {TenantId = "xxxxxxx" });
ServiceBusClient client = new ServiceBusClient("xxx.servicebus.windows.net", tokenCredential);
Specify the exact tenant id by adding the following key to local.settings.json.
"AZURE_TENANT_ID": "your tenant id"
I tried to create an azure function that receives messages from a service bus queue using a managed identity trigger and it worked for me.
late to the party but I got it working on my local Visual Studio with this code
var tokenCredential = new VisualStudioCredential(new VisualStudioCredentialOptions { TenantId = "xxx-xxx" });
ServiceBusClient client = new ServiceBusClient("my-name-space.servicebus.windows.net", tokenCredential);
sender = client.CreateSender('my-topic');
var msgBody = new Person{ Name = 'joe'};
await sender.SendMessageAsync(new ServiceBusMessage(JsonConvert.SerializeObject(msgBody)));
Also, remember to sign in to Azure in your Visual Studio,
and assign your account to the role "Azure Service bus Data Sender" , see below:

How to get a list of app registrations in Azure tenant

I need to get a list of app registrations in my Azure tenant.
I am using the tutorial found here.
Also, I granted permission to my app per this document.
I modified the sample app code as follows:
// Constants.cs
public const string ApplicationReadAll = "Application.Read.All";
Startup.cs:
// Added permission to read all applications
services.AddWebAppCallsProtectedWebApi(Configuration, new string[] { Constants.ScopeUserRead, Constants.CalendarsReadWrite, Constants.ApplicationReadAll })
.AddInMemoryTokenCaches();
HomeController.cs:
// Get list of applications.
Graph::GraphServiceClient graphClient = GetGraphServiceClient(new[] { Constants.ApplicationReadAll });
try
{
var me = await graphClient.Applications.Request().GetAsync();
ViewData["Me"] = me;
}
I have five apps registered in my tenant. The response returns zero, as it does when I make the call from Graph Explorer. I am logging in as Global Admin.
See also this question.
Here is what I discovered:
Directory.Read.All permission is required. Application.Read.All doesn't cut it.
The application (ClientID) that you use must have it's Supported account type set to "My organization only".
If necessary you can change this in the Manifest as follows:
"signInAudience": "AzureADMyOrg",
Full credit and many thanks to Mark Foppen. Read his excellent blog post and see his code on github.

Simple Directory Lookup in Azure Active Directory

I am writing a simple desktop application that needs to retrieve some basic properties about a user from Microsoft’ directory. Specifically:
I am writing a single tenant native LOB application.
The application runs on my desktop.
The application runs as my logged on domain account.
The organization' domain accounts are synced to AAD.
I am not trying to secure a native web app or a Web API or anything like that. I do not need users to sign in.
I have email addresses of folks in my organization from an external event management tool. I need to lookup the AAD account profile data (address book info - specifically job title) from AAD based on the email address. I will only be reading AAD data.
So far, I have done the following:-
It appears that the Azure AD Graph API is the right way to fetch the profile information. In particular, the information is available at the endpoint: https://graph.windows.net/{tenant}/users/{email}?api-version=1.6
When registering the native application in AAD, no key was provided. So I don't have a client secret.
Looked at the sample in GitHub here: https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console. The instructions here seem to be wrong because no Keys section is available [see (2)].
Based on the sample above, I wrote a simple function. Code is below:
private static async Task PrintAADUserData(string email)
{
string clientId = "0a202b2c-6220-438d-9501-036d4e05037f";
Uri redirectUri = new Uri("http://localhost:4000");
string resource = "https://graph.windows.net/{tenant}";
string authority = "https://login.microsoftonline.com/{tenant}/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authority);
AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, clientId, redirectUri, new PlatformParameters(PromptBehavior.Auto));
string api = String.Format("https://graph.windows.net/{tenant}/users/{0}?api-version=1.6", email);
LOG.DebugFormat("Using API URL {0}", api);
// Create an HTTP client and add the token to the Authorization header
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
HttpResponseMessage response = await httpClient.GetAsync(api);
string data = await response.Content.ReadAsStringAsync();
LOG.Debug(data);
}
Questions
The application when run was able to bring up the authentication page. Why do I need that? The application already runs as my domain account. Is an additional authentication necessary? If I were to run this application in Azure as a worker process, then I would not want to use my domain credentials.
The primary problem seems to be the resource URL which is wrong. What resource do I need to specify to access the Azure AD Graph API?
Thanks,
Vijai.
EDITS
Based on the comments from #Saca, the code and application has been edited.
Code
string clientId = ConfigurationManager.AppSettings["AADClientId"];
string clientSecret = ConfigurationManager.AppSettings["AADClientSecret"];
string appIdUri = ConfigurationManager.AppSettings["AADAppIdURI"];
string authEndpoint = ConfigurationManager.AppSettings["AADGraphAuthority"];
string graphEndpoint = ConfigurationManager.AppSettings["AADGraphEndpoint"];
AuthenticationContext authContext = new AuthenticationContext(authEndpoint, false);
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://graph.windows.net", new ClientCredential(clientId, clientSecret));
ExistingTokenWrapper wrapper = new ExistingTokenWrapper(authResult.AccessToken);
ActiveDirectoryClient client = new ActiveDirectoryClient(new Uri(graphEndpoint), async () => await wrapper.GetToken());
IUser user = client.Users.Where(_ => _.UserPrincipalName.Equals(email.ToLowerInvariant())).Take(1).ExecuteSingleAsync().Result;
App
Error
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> Microsoft.Data.OData.ODataErrorException: Insufficient privileges to complete the operation. ---> System.Data.Services.Client.DataServiceQueryException: An error occurred while processing this request. ---> System.Data.Services.Client.DataServiceClientException: {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}
It appears that despite giving the right permissions, the correct resource and being able to acquire a token, there is still something missing.
The key thing to consider here is if your application will be a headless client run from a secure server or desktop client run by users on their machines.
If the former, then your application is considered a confidential client and can be trusted with secrets, i.e. the keys. If this is your scenario, which is the scenario covered by the sample, then you need to use clientId and clientSecret.
The most likely reason you are not seeing a Keys section in the your application's Configure page is that, instead of selecting Web Application and/or Web API as per step #7 in the sample, you selected Native Client Application when first creating the application. This "type" can't be changed, so you'll need to create a new application.
If your scenario is the latter, then your application is considered a public client and can't be trusted with secrets, in which case, your only options is to prompt the user for credentials. Otherwise, even if your app has it's own authorization layer, it can easily be decompiled and the secret extracted and used.
Your resource URL is correct by the way.
Turns out the real issue was not with the code. I am not an AAD administrator. It appears that any application needing to perform authentication against AAD in our tenant needs to have permissions enabled by the AAD administrators. Once they enabled permissions for my application (and took ownership of the AAD registration as well), this started working.
Hope help some one that are using GraphClient:
var userPriNam = "johndoe#cloudalloc.com";
var userLookupTask = activeDirectoryClient.Users.Where(
user => user.UserPrincipalName.Equals(userPriNam, StringComparison.CurrentCultureIgnoreCase)).ExecuteSingleAsync();
User userJohnDoe = (User)await userLookupTask;
from https://www.simple-talk.com/cloud/security-and-compliance/azure-active-directory-part-5-graph-api/

Resources