Generate user token from AuthenticationContext - c#

I am trying to generate a user token for the purpose of testing an API that requires one. The tests run automatically. I have the following code example, but it seems to be out of date
Uri endpointUri = new Uri("my endpoint");
string resource = "my rid";
string clientId = "my client id";
PlatformParameters parameters = new PlatformParameters(PromptBehavior.Auto);
string authContextURL = "my url";
var authenticationContext = new AuthenticationContext(authContextURL, new TokenCache());
// Here you are sending a request to AAD with the user credentials.
AuthenticationResult result = await authenticationContext.AcquireTokenAsync(resource: resource, clientId: clientId, redirectUri: endpointUri, parameters);
// If the request succeeded you can get the user access token as follows.
return result.AccessToken;
The reason I believe it to be out of date is that PlatformParameters now requires 2 parameters, and I cannot find what the 2nd parameter should be by default.
My question is, how can I create a user-context token to use in testing my API from the test code?
EDIT
According to this answer, PlatformParameters with 1 param is for .netframework, whereas I am using .net 6
Still looking to any leads there may be!

Related

Code: BadRequest Message: /me request is only valid with delegated authentication flow

I am trying to upload file on onedrive by using microsoft graph onedrive api.
I am using the method for authentication
Client credentials provider
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
Like:
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "my-tenantid";
// Values from app registration
var clientId = "YOUR_CLIENT_ID";
var clientSecret = "YOUR_CLIENT_SECRET";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
HttpPostedFileBase file = Request.Files;[0];
int fileSize = file.ContentLength;
string fileName = file.FileName;
string mimeType = file.ContentType;
Stream fileContent = file.InputStream;
var res = await graphClient.Me.Drive.Root.ItemWithPath(fileName).Content
.Request()
.PutAsync<DriveItem>(fileContent);
After executing this code then it gives an error in response.
Message: /me request is only valid with delegated authentication flow.
Inner error:
AdditionalData:
date: 2021-12-29T05:30:08
request-id: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
client-request-id: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
ClientRequestId: b51e50ea-4a62-4dc7-b8d2-b26d75268cdc
Client credential flow will generate the token on behalf the app itself, so in this scenario, users don't need to sign in first to generate the token stand for the user and then call the api. And because of the design,when you used Me in the graph SDK, your code/app don't know who is Me so it can't work. You should know the user_id first and use /users/{id | userPrincipalName} instead of /Me, in the SDK, that is graphClient.Users["your_user_id"] instead of graphClient.Me
In your scenario, there're 2 solutions, one way is using delegated authentication flow like what you said in your title, another way is get the user id before calling the graph api so that you can use Users["id"] but not Me
===================== Update=========================
I haven't finished the code yet but I found the correct solution now.
Firstly, we can upload file to one drive by this api, you may check the screenshot if this is one drive or sharepoint:
https://graph.microsoft.com/v1.0/users/user_id/drive/items/root:/testupload2.txt:/content
If it is, then the next is easy, using the code below to get an access token and send http request to calling the api:
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "your_azuread_clientid";
var clientSecret = "corresponding_client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var tokenRequestContext = new TokenRequestContext(scopes);
var token = clientSecretCredential.GetTokenAsync(tokenRequestContext).Result.Token;
I know it's complex because the api is not the same as this one which has SDK sample, but I think it also deserves to try if they are similar.

Get user data from a TokenCredential object (.NET)

I'm building a .NET core tool (Console app) that needs to access some Azure Keyvault secrets by using a SecretClient. This client needs a TokenCredential for which I use DefaultAzureCredential().
The client is successfully authenticated and retrieves the secrets, but can I know which method from the flow was used (i.e. Environment, Cache, CLI, interactive)? I want to display the username that was used for logged in, since you might have an account in SharedCache but you might want to use another account.
var credentials = new DefaultAzureCredential();
var secretClient = new SecretClient(new Uri(configuration["Authentication:KeyVaultUri"]), credentials);
// Just using the client to retrieve values
var settings = JsonSerializer.Deserialize<AppSettingsKeys>((await secretClient.GetSecretAsync(configuration["Authentication:SecretName"])).Value.Value);
I checked the credential object but didn't see anything useful to get the username. I want to Console.WriteLine something like Successfully logged in with pepe#test.com using SharedTokenCacheCredential
I was able to get the upn by first getting the jwt with the GetToken method, and then parsing it with a JwtSecurityTokenHandler.
Not the approach I was looking for but it works, I was wondering if there is cleaner way.
var credential = new DefaultAzureCredential();
var secretClient = new SecretClient(new Uri(configuration["Authentication:KeyVaultUri"]), credential);
var settings = JsonSerializer.Deserialize<AppSettingsKeys>((await secretClient.GetSecretAsync(configuration["Authentication:SecretName"])).Value.Value);
var token = await credential.GetTokenAsync(
new Azure.Core.TokenRequestContext(
new[] { "https://vault.azure.net/.default" }));
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(token.Token) as JwtSecurityToken;
var upn = jsonToken.Claims.First(c => c.Type=="upn").Value;

AADSTS70011: The provided value for the input parameter 'scope' is not valid

So I have a scenario wherein the application should add users to a group on certain conditions. Also when the application starts running users should not be asked to login their microsoft id/pwd.
So I access the token I created using Graph Service Client object as follows:
GraphServiceClient graphClient = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string clientId = "My APP ID";
string authorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
string tenantId = "tenant GUID";
string[] _scopes = new string[] {
"https://graph.microsoft.com/User.ReadBasic.All"
};
// Custom Redirect URI asigned in the Application Registration
// Portal in the native Application Platform
string redirectUri = "https://localhost:4803/";
string clientSecret = "App Secret";
ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(
clientId,
String.Format(authorityFormat, tenantId),
redirectUri,
new ClientCredential(clientSecret),
null, new TokenCache()
);
AuthenticationResult authResult = await daemonClient.AcquireTokenForClientAsync(_scopes);
string token = authResult.AccessToken;
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
}
)
);
So I try to execute
var user = await graphClient.Me.Request().GetAsync();
I get this error:
AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope user.read is not valid.
I also tried using just User.ReadBasic as scope, but get the same error.
What am I doing wrong here?
You are using the client credential flow here, which means that you cannot dynamically request scopes. You must configure your required permission scopes on your app registration in apps.dev.microsoft.com, then you set the value of scope in your code to https://graph.microsoft.com/.default.
See https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service for more details.
I reccomend to use .defuault scope
The .default scope is used to refer generically to a resource service (API) in a request, without identifying specific permissions...
Clients can't combine static (.default) consent and dynamic consent in a single request. So scope=https://graph.microsoft.com/.default Mail.Read results in an error because it combines scope types.
For set your Scope var in C#
string[] scope = new string[] {".default"};
For set your Scope var Java
private final List<String> scope = Arrays.asList(".default");
I had copied code from another authorize that was working for a user not an organization.
So I received the error because I had the wrong grant_type.
Make sure yours is "client_credentials"

How to export azure database to blob storage

I need to know exactly how to login to Azure, using c#.
I basically want to do this, but from the code:
]a link](https://learn.microsoft.com/en-us/azure/sql-database/sql-database-export)
Here is the code I copied from the internet trying to achieve this:
But I don't know how to generate the token.
SqlManagementClient managementClient = new SqlManagementClient(new TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
var exportParams = new DacExportParameters()
{
BlobCredentials = new DacExportParameters.BlobCredentialsParameter()
{
StorageAccessKey = storageKey,
Uri = new Uri(baseStorageUri)
},
ConnectionInfo = new DacExportParameters.ConnectionInfoParameter()
{
ServerName = azureSqlServer,
DatabaseName = azureSqlDatabase,
UserName = adminLogin,
Password = adminPassword
}
};
var exportResult = managementClient.Dac.Export(azureSqlServerName, exportParams);
I have a GetToken function, but I have no idea where to take the
tenant + client id + secret
private static string GetAccessToken(string tenantId, string
clientId, string secretKey)
{
var authenticationContext = new
AuthenticationContext($"https://login.windows.net/{tenantId}");
var credential = new ClientCredential(clientId, secretKey);
var result =authenticationContext
.AcquireTokenAsync("https://management.core.windows.net/",
credential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
var token = result.Result.AccessToken;
return token;
}
This question was asked before
Azure Database export with C#
but I need to see the actual code and explanation on how to get the connection info.
I need to see the actual code and explanation on how to get the connection info.
I would recommend you follow this tutorial about registering your AAD application and adding the secret key. Moreover, you could also follow Using the Azure ARM REST API – Get Access Token.
SqlManagementClient managementClient = new SqlManagementClient(new TokenCloudCredentials(subscriptionId, GetAccessToken(tenantId, clientId, secretKey)));
Based on your code, I assumed that you are using the package Microsoft.WindowsAzure.Management.Sql, if you use the TokenCloudCredentials, you may receive the following error response:
AFAIK, Microsoft.WindowsAzure.Management.Libraries requires the X509Certificate2 authentication, you need to construct the CertificateCloudCredentials for your SqlManagementClient. For uploading a management certificate under your subscription, you could follow Upload an Azure Service Management Certificate. For retrieving the X509Certificate2 instance, you could follow the code snippet under the Authenticate using a management certificate section from here.
For token-based authentication, you could use the package Microsoft.Azure.Management.Sql and construct your SqlManagementClient as follows:
var sqlManagement = new SqlManagementClient(new TokenCredentials("{access-token}"));
Moreover, you need to change the resource from https://management.core.windows.net/ to https://management.azure.com/ when invoking the AcquireTokenAsync method.

How to get On-Behalf-Of-User token in .NET using ADAL

I have created an Azure AAD app of type webapp which has client secret and redirect url. Now, I want to get an access token on behalf of user using the AAD app. From looking at the documentation, I got the following code so far.
static void Main(string[] args)
{
var clientId = "<REDACTED>";
var clientSecret = "<REDACTED>";
var resourceAppIdURI = "https://api.office.com/discovery/";
var authority = "https://login.microsoftonline.com/common";
AuthenticationContext ac = new AuthenticationContext(authority, new FileCache());
ClientCredential cc = new ClientCredential(clientId, clientSecret);
// Get token as application
var task = ac.AcquireTokenAsync(resourceAppIdURI, cc);
task.Wait();
var appToken = task.Result.AccessToken;
// Get tokenn on behalf of user
UserCredential uc = new UserCredential("usrname#mytenant.com");
task = ac.AcquireTokenAsync(resourceAppIdURI, clientId, uc);
var userToken = task.Result.AccessToken;
Console.ReadLine();
}
But this is the error I get when I try to get user token is as follows.
Message "AADSTS70002: The request body must contain the following
parameter: 'client_secret or client_assertion'.\r\nTrace ID:
0e977f67-d5cb-4cf5-8fea-bac04b6d0400\r\nCorrelation ID:
824a96bf-8007-4879-970c-2680644b8669\r\nTimestamp: 2017-07-21
05:02:41Z" string
Why am I getting this error and how to fix it?
Do I need to login with the user first and then use UserAssertion instead ?
There are tonnes of overloaded methods for AcquireTokenAsync method, but not sure what I should use.
I also looked at this github url to see how they are doing it
https://github.com/Azure-Samples/active-directory-dotnet-webapi-onbehalfof/blob/8afb3e6a648d8e7246685bf6747d009006c761b8/TodoListService/Controllers/TodoListController.cs
This is the relevant code to get token as logged in user
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(authority, new DbTokenCache(userId));
Here they already have a logged in user and creating a UserAssertion from that loggedin user's token. In my console app, the user hasn't logged in yet.
So I need a way to do this in my console app. How can I show the AAD login page to the user as a pop-up and then once the user enters creds use that info to create an UserAssertion object?
thanks
Your scenario is a native application that calls a web API on behalf of a user . The native application could obtains an access token for the user by using the OAuth 2.0 authorization code grant , then access token is then sent in the request to the web API, which authorizes the user and returns the desired resource :
Please read more about the description of protocol flow here .Also see the code samples for Native Application to Web API scenarios.
In addition , you could click here for code sample about how to call the Azure AD Graph API from a native client(.net console application ) ,it uses the Active Directory Authentication Library (ADAL) for authentication .

Categories

Resources