Programatically SetSecrets to Key Vault in C# using DefaultAzureCredential() - azure-keyvault

Can someone please help me with the following error:
Azure.RequestFailedException
HResult=0x80131500
Message=Service request failed.
Status: 401 (Unauthorized)
Content:
{"error":{"code":"Unauthorized","message":"AKV10032: Invalid issuer. Expected one of https://sts.windows.net/db8e2ba9-95c1-4fbb-b558-6bf8bb1d2981/, https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/, https://sts.windows.net/e2d54eb5-3869-4f70-8578-dee5fc7331f4/, found https://sts.windows.net/6e51e1ad-c54b-4b39-b598-0ffe9ae68fef/."}}
This is my code:
protected string CreateVendorApiServerSecret(string name, string secret)
{
var client = new SecretClient(new Uri(KeyvaultUri), new DefaultAzureCredential());
var secret = new KeyVaultSecret(name, secret);
client.SetSecret(secret, default); //I get the error here
KeyVaultSecret getSecret = client.GetSecret(name);
string identifier = getSecret.Id.ToString();
return identifier;
}
If I give TenantId in the config files. It gives the following error:
Message=DefaultAzureCredential failed to retrieve a token from the included credentials.
EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
SharedTokenCacheCredential authentication unavailable.

Adding the following code at initial startup worked for us:
const string tenantId = "put-tenant-id-here";
Environment.SetEnvironmentVariable( "AZURE_TENANT_ID", tenantId );

Please learn details about DefaultAzureCredential.
Environment - The DefaultAzureCredential will read account information
specified via environment variables and use it to authenticate.
Managed Identity - If the application is deployed to an Azure host
with Managed Identity enabled, the DefaultAzureCredential will
authenticate with that account.
Visual Studio - If the developer has authenticated via Visual Studio,
the DefaultAzureCredential will authenticate with that account.
Visual Studio Code - If the developer has authenticated via the Visual
Studio Code Azure Account plugin, the DefaultAzureCredential will
authenticate with that account.
Azure CLI - If the developer has authenticated an account via the
Azure CLI az login command, the DefaultAzureCredential will
authenticate with that account.
Interactive - If enabled the DefaultAzureCredential will interactively
authenticate the developer via the current system's default browser.
I'm not sure you are using which mechanism to authenticate.
The easiest way is sign in Visual Studio with your Azure account. Then the DefaultAzureCredential will authenticate with that account.
No matter which mechanism you are using, make sure that the account has access to the key vault which you are trying to set secret into.
In your case, the reason should be you are using an account which may be probably from another tenant. Please check.
There is an official sample here.
Use Visual Studio to open the project and then sign in VS with your Azure account. Make sure this account has access to your Azure Key Vault.
Replace string keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME"); with string keyVaultName = "{your own key vault name}"; {your own key vault name} should be an existing key vault which you have created.

Ok. I ran into the same issue and this solved my problem. Hope this helps. mine actually dealt with Microsoft Account authentication.
I have two Microsoft accounts and only one is authorized to access resources in my Azure portal.
In visual studio go to file and accounts.
Log out of all accounts.
Log back into the account that has access to the azure resource.
Re-Run code and if authentication was your issue, you are golden. If not don't vote me down for sharing an alternative unless your a dick.

If you are using Visual Studio then set tenant id in DefaultAzureCredentialOptions.
you can also use InteractiveBrowserTenantId
e.g.
var azureCredentialOptions = new DefaultAzureCredentialOptions();
#if DEBUG
azureCredentialOptions.SharedTokenCacheUsername = "name.surname#company.com";
//azureCredentialOptions.InteractiveBrowserTenantId = tenantId;
azureCredentialOptions.VisualStudioTenantId = tenantId;
#endif
DefaultAzureCredential credential = new DefaultAzureCredential(azureCredentialOptions);
var client = new SecretClient(new Uri(kvUri), credential);

Related

Get Azure AD directory users in a Rails app

I have a Rails 6 application and I want to use Azure Active Directory as an authentication system (with open id connect, saml2 and ldap).
The authentication is done.
Now I am trying to display user information like names or email addresses. I also want to be able to export all users of a directory.
I have tried to set a configuration up like so:
In my Rails app, in the admin panel, an admin can configure Azure AD for my application
in the config, the admin copies and pastes the configuration link provided by Azure AD (a JSON response)
Then, copies and pastes the app client_id
Then, the tenant_id (directory id)
Here is a piece of code that I expected to work:
def update_oidc
identity_provider = IdentityProvider.find_by(provider_type: 'open_id_connect', id: params[:id])
client_id = params[:client_id].strip
metadata_url = params[:metadata_url].strip
tenant_id = params[:tenant_id].strip
metadata = HTTParty.get(metadata_url).parsed_response
identity_provider.update(config: {
metadata: metadata,
metadata_url: metadata_url,
client_id: client_id,
tenant_id: tenant_id,
})
if tenant_id
directory_access_url = "https://graph.windows.net/#{tenant_id}/users?api-version=1.6"
result = HTTParty.get(directory_access_url).parsed_response
identity_provider.directories.find_or_create_by(tenant_id: tenant_id).update(
business_phones: result["business_phones"],
display_name: result["display_name"],
given_name: result["given_name"],
job_title: result["job_title"],
email: result["user_principal_name"],
mobile_phone: result["mobile_phone"],
office_location: result["office_location"],
surname: result["surname"]
)
end
redirect_to identity_provider
end
As the tenant_id is the directory id, i thought that we might be able to access user info this way (and following the Microsoft Docs). The thing is, it doesn't work because even though I'm connected to my Azure AD directory in my app, when I run result = HTTParty.get(directory_access_url).parsed_response, i have an authentication error telling me the token has expired or that i need to be connected.
I don't want to use PowerShell or anything like this. I want to be able to access directories data through my app.
Can someone tell me what i'm doing wrong or come up with an idea ?
Thanks
Just according to your code, I think you want to get the collection of users via the Azure AD Graph REST API Get users using jnunemaker/httparty library.
However, it seems to be missing the required header Authorization with its value like Bearer eyJ0eX ... FWSXfwtQ as the section Authentication and authorization of the offical document Operations overview | Graph API concepts said. Meanwhile, you have done the authentication with OpenID Connect, but Azure AD Graph API requires the access token as Authorization value from OAuth2 as the content below said.
The Graph API performs authorization based on OAuth 2.0 permission scopes present in the token. For more information about the permission scopes that the Graph API exposes, see Graph API Permission Scopes.
In order for your app to authenticate with Azure AD and call the Graph API, you must add it to your tenant and configure it to require permissions (OAuth 2.0 permission scopes) for Windows Azure Active Directory. For information about adding and configuring an app, see Integrating Applications with Azure Active Directory.
Azure AD uses the OAuth 2.0 authentication protocol. You can learn more about OAuth 2.0 in Azure AD, including supported flows and access tokens in OAuth 2.0 in Azure AD.
So I'm afraid you have to get the access token manually via OAuth2 for Azure AD again for using Graph API, or just simply refer to the sample code samples/authorization_code_example/web_app.rb using the adal library of GitHub repo AzureAD/azure-activedirectory-library-for-ruby for Ruby.

How get Azure KeyVault secret for C# IIS application running on premise

Is there any way to get a key vault secret using the IIS app pool identity to authenticate?
The typical solution for reading values from Azure KeyVault is
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
result = await keyVaultClient.GetSecretAsync(secretUrl).ConfigureAwait(false);
While this work under visual studio, and even for a Windows/console application, it doesn't work for an IIS application - even when the app pool is configured with an identity that would otherwise work.
All the solutions I've found to date require a service principle and supplying its id and secret which - and it's storing secrets locally that I'm trying to avoid.
Example: https://blog.bitscry.com/2019/02/13/using-azure-key-vault-in-a-console-application/
var keyClient = new KeyVaultClient(async (authority, resource, scope) => {
var adCredential = new ClientCredential(clientId, clientSecret);
var authenticationContext = new AuthenticationContext(authority, null);
return (await authenticationContext.AcquireTokenAsync(resource, adCredential)).AccessToken;
});
Is there any way to get a key vault secret using the IIS app pool identity to authenticate?
For local development authentication, AzureServiceTokenProvider fetches tokens using Visual Studio, Azure command-line interface (CLI), or Azure AD Integrated Authentication.
Using Visual Studio and Azure CLI both need to sign in to azure. And the User should be add to Access Policy of Azure keyvault.
Using Azure ad Integrated authentication, you also need to add the service principal into the Access Policy .
However, if you want to use IIS app pool identity to authenticate, you could not add Application Pool Identity Accounts to Azure keyvault. So, you could not avoid to use service principal's id and secret to authenticate.

TF400813: The user {userguid}is not authorized to access this resource [duplicate]

This question already has answers here:
VssClientCredentials with accesstoken credentials in VSTS authentication
(3 answers)
Closed 4 years ago.
I am getting below error when reading licensing information of user in VSTS.
TF400813: The user 'userguid' is not authorized to access this
resource.
VssOAuthAccessTokenCredential accessTokenCredentials = new VssOAuthAccessTokenCredential(new VssOAuthAccessToken(accessToken));
var credentials = new VssClientCredentials(accessTokenCredentials);
credentials.Storage = new VssClientCredentialStorage();
VssConnection connection = new VssConnection(new Uri(this.ServerUri), credentials);
var licensingHttpClient = connection.GetClient<LicensingHttpClient>();
var accountEntitlement = licensingHttpClient.GetAccountEntitlementAsync().Result;
var license = accountEntitlement.License;
Firstly make sure you have the correct permission to read the licensing information.
The issue is mainly caused by the VSTS account is not connect with the AAD which your user account is stored in.
If the email address is not a Microsoft email, it will be backed to AAD when connecting the VSTS account. If the client VSTS is not connected this AAD or connected with another AAD, you will not be authorized to login the client VSTS account.
Just try below things to narrow down the issue:
Connect VSTS to Azure AAD
Detail information about connect VSTS account to AAD, you can refer
here.
Use Microsoft email login your client VSTS account.
You can use a Microsoft email address (such as user#outlook.com or
user#hotmail.com etc). Just add the Microsoft email to the VSTS
account.

How do I authenticate against the Dynamics 365 Data Export Service API?

I've set up something called the Data Export Service for Dynamics 365 so that it replicates into an Azure SQL database. This is working as expected.
I'm trying to find a way to be proactively notified if this service encounters any errors. There does not appear to be a native way to do this through the setup in CRM itself, but they do provide an API. The Swagger page outlining all methods can be found here.
I'm trying to call the GetProfilesByOrganizationId method using Postman:
https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=4ef7XXXX-XXXX-XXXX-XXXX-XXXXXX8a98f&status=true
I'm having issues with authentication and always receive the following error:
"Message": "Received unauthenticated requestRequest Url https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=4ef7XXXX-XXXX-XXXX-XXXX-XXXXXX8a98f&status=true"
I have registered an application in Azure that has permission to access Dynamics 365 on behalf of the authenticated user which in this case is me, the administrator.
I have set the Type to OAuth 2.0 on the Authorization tab of Postman. I have requested an Access Token using the Grant Type of Authorization Code against the above application successfully. This has added a header to the request:
Key: Authorization
Value: Bearer BIGLONGACCESSTOKEN
Despite this header being present I still get the error mentioned above.
The API documentation implies the authentication is OAuth2 Implicit Grant Flow (click on any red exclamation mark in the documentation) but I can't get this to work in Postman. When I try to request a token with this method I get the error:
unsupported_response_type
... in the Postman console.
Any ideas how to authenticate (with Implicit Grant?) against this API in Postman?
(I'd accept C# examples if they're more appropriate, but I'd be surprised if Postman can't show me what I need)
It looks like the code sample shown by Microsoft can work if updated with newer methods and with some extra configuration in Azure that's not documented.
Azure configuration
By installing the Data Export service (and assuming it's all working) you'll have a new Enterprise Application listed in Azure AD as Crm Exporter.
To take advantage of this application and authenticate with the Data Export API you must configure an app of your own.
Go to the App registrations tab in Azure AD and add a new application registration.
Give it a name and set the Application type to Native. The redirect URI doesn't typically matter as long as it's valid.
Click the Manifest button to edit the manifest, change the property oauth2AllowImplicitFlow to true and save the changes.
The only other important configuration is Required permissions which should be set as below:
Windows Azure Active Directory
Delegated permissions
Sign in and read user profile
Data Export Service for Microsoft Dynamics 365 (Crm Exporter)
Delegated permissions
Have access to Data Export Service for Microsoft Dynamics 365 API
You will then need to click Grant Permissions.
C# changes
The updated method looks like this:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
string clientId = "11cfXXXX-XXXX-XXXX-XXXX-XXXXXXXXd020";
string user = "my.username#domain.com";
string password = "PASSWORD";
var authParam= await AuthenticationParameters.CreateFromResourceUrlAsync(
new Uri("https://discovery.crmreplication.azure.net/crm/exporter/aad/challenge")
);
var context = new AuthenticationContext(authParam.Authority, false);
var credentials = new UserPasswordCredential(user, password);
var token = await context.AcquireTokenAsync(authParam.Resource, clientId, credentials).AccessToken;
You can now query the Data Export API by providing the token as a header:
Authorization : Bearer eJ0y........Hgzk
curl -X GET --header 'Accept: application/json' 'https://discovery.crmreplication.azure.net/crm/exporter/profiles?organizationId=MyOrgId&status=true'

Call secure Azure API from Azure Scheduler

I have developed an Azure API which is secure with "log in with azure active directory" configured in ExpressMode.
In Azure management portal, under application, choosing the registered app
in configure section I copied , Client ID and generated key
Now I need to call this API , from azure scheduler, I configured Authentication setting under job Action setting to use "Active Directory OAuth" and I entered the related value for Tenant, ClientId , Secret and for Audience I left the default value which is : https://management.core.windows.net/
but when I try to run the job will be failed
Unauthorized' Response Headers:...
body : You do not have permission to view this directory or page.
I was wondering which part I have missed to configure?
Thanks!
after some more research, finally found answer, Thanks to the
"Unauthorized" when invoking an API App from Azure Scheduler with Azure AD OAuth authentication
Browse to AzureResource Explorer
Select your API app , under config select authsettings node
Edit "allowedAudiences" like below
"allowedAudiences": [
"https://xxxx.azurewebsites.net",
"https://management.core.windows.net/"
],

Resources