Generate bearer token client side C# - c#

Im am working with a REST service deployed in an azure environment. I want to run some integration testing by calling various API functions from a separate (console) application. But the REST api uses bearer token authentication. Im a total noob with azure authentications, so i don't even know if it should be possible.
I've tried to use the example found here but no luck yet.
In anycase, I have two applications. One is the console app that is running the code, and the other is the Rest service for which i need to use the bearer token to access the API calls. I will call them the ConsoleApp and RestService.
The code I run is as following:
HttpClient client = new HttpClient();
string tenantId = "<Azure tenant id>";
string tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
string resourceUrl = "<RestService app id url>";
string clientId = "<azure id of the ConsoleApp>";
string userName = "derp#flerp.onmicrosoft.com";
string password = "somepassword";
string tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
var body = $"resource={resourceUrl}&client_id={clientId}&grant_type=password&username={userName}&password={password}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
var result=await client.PostAsync(tokenEndpoint, stringContent).ContinueWith<string>((response) =>
{
return response.Result.Content.ReadAsStringAsync().Result;
});
JObject jobject = JObject.Parse(result);
The Json message I get back:
error: invalid_grant, error_description: AADSTS50105: The signed in
user is not assigned to a role for the application "RestService
azureid"
What does that mean, and how what needs to be done to get a bearer token out of this?

Please firstly check whether you enabled the User assignment required of console application :
In your azure ad blade ,click Enterprise applications ,search your app in All applications blade ,click Properties :
If enabled that , and your account not assigned access role in your app , then you will get the error . Please try to assign access role in your app :
In your azure ad blade ,click Enterprise applications ,search your console app in All applications blade ,click Users and groups , click Add User button , select your account and assign role(edit user and ensure select role is not None Selected):
Please let me know whether it helps.

Related

Authenticate Azure AD using Provided Access Token

I tried to find an Azure authentication mechanism that uses an access token as a parameter. but no luck. I just found ClientSecretCredential class that use tenant id, client id, and client secret as a parameter like below :
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
the reason I need the that is the access token will be generated by another service and my service will only accept access token to be used to authenticate Azure AD.
Actually, I can utilize Azure Management RestAPI to do that. However to improve developer experience I'd like to utilize .NET client library if possible.
I have tried to find documentation in Azure Identity client library in https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet, but I couldn't find any class or method that I need.
If you want tokens from azure ad you can use using Microsoft.IdentityModel.Clients.ActiveDirectory; library to get the tokens.
I am assuming that you have already created an azure ad app registration and already possess the client_id , client_secret and tenant_id. Just save this as strings in code.
Now we can use the clientcredential along with authenticationContext we can acquire tokens.
Complete program :
string client_id = "";
string client_secret = "";
string tenant_id = "";
string endpoint = "https://login.microsoftonline.com/"+tenant_id;
ClientCredential credent = new ClientCredential(client_id , client_secret);
var context = new AuthenticationContext(endpoint);
var result = context.AcquireTokenAsync("https://management.azure.com/",credent);
var result = context.AcquireTokenAsync("https://management.azure.com/",credent);
Console.WriteLine(result.Result.AccessToken);
Here result.Result.AccessToken will give you a access token in form of a token.

Microsoft Graph list buckets with clientsecretcredentials

I am trying to manipulate microsoft planner tasks (end goal is to create a task in a certain Scope and bucket).
I am already failing at listing a Plan or the buckets for a plan. I want to make this connection from a background service (daemon) so no interactive user login should take place. (with interactive login credentials i can make it work, but that's not what i need/want).
So i Created a new App Registration in Azure with the Api Permissions:
Group.Read.All (Delegated)
Group.ReadWrite.All (Delegated)
Tasks.Read (Delegated)
Tasks.Read.Shared (Delegated)
Tasks.ReadWrite (Delegated)
Tasks.ReadWrite.Shared (Delegated)
User.Read (Delegated)
Group.ReadWrite.All (Application)
Tasks.ReadWrite.All (Application)
User.ManageIdentities.All (Application)
User.ReadWrite.All (Application)
I also checked the "Allow public client flows" setting on the App registration Authentication tab.
I started by adding the ones prescribed on the official microsoft doc website about this topic. And then started adding some because i was still receiving Access Denied messages. Thus reaching this list. It should be enough according to microsoft.
Then i have this code to authenticate with Microsoft graph, giving me a graphclient instance which is successfully initialized:
private GraphServiceClient initializeTeamsGraphConnection(string TenantId, string ApplicationId, string ClientSecret)
{
// The client credentials flow requires that you request the
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { ScopeGraph };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = TenantId;
// Values from app registration
var clientId = ApplicationId;
var clientSecret = ClientSecret;
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://docs.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
return graphClient;
}
So authentication seems to be succesful, but when i then try to list a plan using the code below:
private void CreateTask(GraphServiceClient client)
{
var graphTask = client.Planner.Plans["Sdonp-JNB0aInPxDcxMowZgACZ59"]
.Request()
.GetAsync();
while (!graphTask.IsCompleted)
{
graphTask.Wait(10000);
}
var plans = graphTask.Result;
I get following error:
403 - Forbidden: Access is denied.
You do not have permission to view this directory or page using the credentials that you supplied.
Access Permissions should be well above what is needed to do this. Any idea on what I am doing wrong?
Again this code is working because when i change authentication to some sort of interactive login type, i get this plan info no problem
Planner API currently supports only delegated permissions that's the reason why it returns 403 for daemon (background service).
According to this announcement, support for application permissions is coming soon.

Why doesn’t the "https://login.microsoftonline.com/common" AAD endpoint work, while the "https://login.microsoftonline.com/[tenant ID]" does?

I’m developing a UWP application that calls an API. The API is made of an Azure Function triggered by HTTP requests. I want the Azure Function to be secured through Azure Active Directory. To do so, I created two app registrations in AAD, one for the UWP and one for the API. Both support accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g., Skype, Xbox). The API app registration provides scope, and the UWP app registration uses that scope. The code I use on my UWP is:
var HttpClient _httpClient = new HttpClient();
const string clientId = "[UWP app registration’s client ID]";
const string authority = "https://login.microsoftonline.com/[Tenant ID of the UWP app registration]";
string[] scopes = { "api://[API app registration’s client ID]/[scope]" };
var app = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority(authority)
.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
.Build();
AuthenticationResult result;
var accounts = await app.GetAccountsAsync();
try {
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
}
catch (MsalUiRequiredException) {
try {
result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (Exception exception) {
Console.WriteLine(exception);
throw;
}
}
if (result == null) return;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var response = _httpClient.GetAsync("[API URL]").Result;
This code works, but if I replace the authority with https://login.microsoftonline.com/common (as specified here), being my app registrations multi-tenant, I get a 401 response when calling the API _httpClient.GetAsync("[API URL]").Result. The docs say the code must be updated somehow when using the /common endpoint, but I don’t understand how I should edit it. I also tried to follow these tips, but without success, while these seem not to be related to my case since I’m not building an IWA. If I run the working version of the code, result is populated with an object whose TenantId property gets the right value of the tenant that owns the app registrations while using the not-working version of the code, result is populated with an object whose TenantId property gets a value I don’t know where it’s coming from.
Can anyone help me, please?
Here's my understanding of AAD multitenancy flow :
The common authority can't be used to get a token. It's used as a common endpoint to get the templated server metadata :
v1 : https://login.microsoftonline.com/common/.well-known/openid-configuration
v2 : https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
A token should be requested from the issuer where the client is defined.
But the common authority can be used in a multitenant API (eg your Azure Functions API) to verify that a client has a valid AAD token. From the documentation :
Because the /common endpoint doesn’t correspond to a tenant and isn’t an issuer, when you examine the issuer value in the metadata for /common it has a templated URL instead of an actual value : https://sts.windows.net/{tenantid}/
Therefore, a multi-tenant application can’t validate tokens just by matching the issuer value in the metadata with the issuer value in the token. A multi-tenant application needs logic to decide which issuer values are valid and which are not based on the tenant ID portion of the issuer value.

azure data lake authorization

I am new to Azure Data Lake Analytics and am converting a C# batch job to use service to service authentication before submitting stored procedures to Azure Data Lake Analytics.
public void AuthenticateADLUser()
{
//Connect to ADL
// Service principal / appplication authentication with client secret / key
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
cTokenCreds = ApplicationTokenProvider.LoginSilentAsync(strDomain, strWebApp_clientId, strClientSecret).Result;
SetupClients(cTokenCreds, strSubscriptionID);
}
public static void SetupClients(ServiceClientCredentials tokenCreds, string subscriptionId)
{
_adlaClient = new DataLakeAnalyticsAccountManagementClient(tokenCreds);
_adlaClient.SubscriptionId = subscriptionId;
_adlaJobClient = new DataLakeAnalyticsJobManagementClient(tokenCreds);
_adlsFileSystemClient = new DataLakeStoreFileSystemManagementClient(tokenCreds);
}
Even though I have given it the correct ClientId the error comes back with a different ClientID in the error when I execute the following code:
var jobInfo = _adlaJobClient.Job.Create(_adlsAccountName, jobId, parameters);.
The error message is:
The client 'e83bb777-f3af-4526-ae34-f5461a5fde1c' with object id 'e83bb777-f3af-4526-ae34-f5461a5fde1c' does not have authorization to perform action 'Microsoft.Authorization/permissions/read' over scope '/subscriptions/a0fb08ca-a074-489c-bed0-....
Why is the ClientID different than the one I used in the code?
Is this a code issue or a permissions issue? I assume that it is code since the ClientID is not an authorized one that I created.
note: The SubscriptionId is correct.
I assumed you created an Azure Active Directory App and are you the client and domain IDs of this app. If not, you'll need that... If you do have that, then can you check if the App has permissions over your Data Lake Store: https://learn.microsoft.com/en-us/azure/data-lake-store/data-lake-store-authenticate-using-active-directory
Had exactly same symptoms. WebApp was created in AAD in portal originally to access Azure Data Lake Store and same code-snippet worked perfectly. When I decided to re-use same WebApp (clientid/secret) it failed with same error, even though I have given reader/contributor roles on sub/RG/ADLA to the App.
I think the reason is that WebApp underneath has a "service principal" object (thus error msg shows different object id) and ADLA uses it for some reason. Mine didn't have credentials set - empty result:
Get-AzureRmADSpCredential -objectid <object_id_from_error_msg>
Added new password as described here
New-AzureRmADSpCredential -objectid <object_id_from_error_msg> -password $password
Used the pwd as secret in LoginSilentAsync, clientId was left as before - WebApp clientId (not the principal object id shown in the error)
I wasn't able to find this principal info in portal, only PS.

Facebook SDK for .NET: Uploading pics to a page from backend

What I am looking to achieve.
I have a WPF application where in, I will be getting access to some pics generated on run time and I wanna post these pics to an album on FB Page(Think server to server interaction ). This process is supposed to be completely self reliant without any input from users. So I did some research and figured you gotta create an app to be able to do it. On further research the process seems to be as follows:
1) Using app secret and app id , get the app access token
2) Get the user access token
3) using this user access token, call {userId}/accounts and from the resulting JSON parse the page id and get the Page Access token.
Now I have successfully retrieved the App Access token and now I am not able to figure out how to get UserAccessToken without which I cant proceed to step 3.
I am using C# SDK for facebook and here is some code
Step 1.
var fbAccess = new FacebookClient();
dynamic resultAccess = fbAccess.Get("oauth/access_token", new
{
client_id = "XXXXXXXXX",
client_secret = "XXXXXXXXXXX",
grant_type = "client_credentials",
redirect_uri = "",
perms = "manage_pages, photo_upload, publish_stream"
});
String app_access_token = resultAccess["access_token"];
Step 2:
FacebookClient fbClient = new FacebookClient(app_access_token );
dynamic resultAccess = fbClient.Get("/{UserID}/accounts", new
{
client_id = "XXXXXXX",
client_secret = "XXXXXXXXXXXXXXXXX",
perms = "manage_pages, photo_upload, publish_stream"
});
The error I am getting is "A user access token is required to request this resource." I have already given the required permission to the app using Graph API Explorer.
Thanks in Advance

Categories

Resources