Azure Storage Emulator - Configuring CORS dynamically throws Server Authentication error - c#

I'm using Microsoft.WindowsAzure.Storage C# library in .Net Core 2.0.
Using this library I'm trying to configure CORS dynamically in Azure Storage Emulator but getting error:
"Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature".
public async void ConfigureCors() {
ServiceProperties serviceProperties = await this.blobClient.GetServicePropertiesAsync();
serviceProperties.Cors = new CorsProperties();
serviceProperties.Cors.CorsRules.Clear();
serviceProperties.Cors.CorsRules.Add(new CorsRule() {
AllowedHeaders = allowedCorsHeaders,
ExposedHeaders = allowedCorsExposedHeaders,
AllowedOrigins = allowedCorsOrigin,
AllowedMethods = allowedCorsMethods,
MaxAgeInSeconds = allowedCorsAgeInSeconds
});
await blobClient.SetServicePropertiesAsync(serviceProperties);
}
I'm able to generate SAS key for upload files on local server directly, but is not able to configure CORS dynamically so that I can access storage via C# code.
Strange thing to note is that the above code is working perfectly fine when using Azure Storage Cloud but local emulator is throwing this error.
Version info:
WindowsAzure.Storage version is 8.4.0
Windows Azure Storage Emulator version 5.2.0.0
Azure storage explorer version is 0.9.01
Credentials used for connection:
AccountName=devstoreaccount1;
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuF‌​q2UVErCz4I6tq/K1SZFP‌​TOtr/KBHBeksoGMGw==;

According to your description, I have created a test demo on my side. It works well.
I guess the reason why you get the Server failed to authenticate the request error is the wrong azure storage package version and storage emulator version.
I suggest you could update the storage version to 8.4.0 and storage emulator version to 5.2 firstly and try again.
More details about my test demo, you could refer to below codes:
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("UseDevelopmentStorage=true");
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
ServiceProperties serviceProperties = blobClient.GetServicePropertiesAsync().Result;
serviceProperties.Cors = new CorsProperties();
serviceProperties.Cors.CorsRules.Clear();
serviceProperties.Cors.CorsRules.Add(new CorsRule()
{
AllowedHeaders = new List<string>() { "*" },
ExposedHeaders = new List<string>() { "*" },
AllowedOrigins = new List<string>() { "*" },
AllowedMethods = CorsHttpMethods.Put | CorsHttpMethods.Get | CorsHttpMethods.Head | CorsHttpMethods.Post,
MaxAgeInSeconds = 1800
});
var re = blobClient.SetServicePropertiesAsync(serviceProperties);
Result:

Related

Unable to fetch secret value from Key Vault using system managed identity in C# Azure Function

I had enabled system assigned managed identity in azure function(Service bus topic trigger) and added the identity(Object (principal) ID
) in key vault access policy with "Get,List" permissions of secrets, keys. I added the reference of the Key Vault into Azure function Application settings and able to receive at runtime after azure function deployment.
#Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)
Code:
private async Task<string> FetchSecretValueFromKeyvault(string secretName)
{
_logger.LogInformation($"FetchSecretValueFromKeyvault: SecretName {secretName}");
string actualSecret = string.Empty;
try
{
string systemAssignedClientId = GetEnvironmentVariable("AzureADManagedIdentityClientId");
string azureKeyVaultUrl = GetEnvironmentVariable("AzureKeyVaultUrl");
var defaultAzureCredentialOptions = new DefaultAzureCredentialOptions();
defaultAzureCredentialOptions.ExcludeAzureCliCredential = true;
defaultAzureCredentialOptions.ExcludeEnvironmentCredential = true;
defaultAzureCredentialOptions.ExcludeAzurePowerShellCredential = true;
defaultAzureCredentialOptions.ExcludeInteractiveBrowserCredential = true;
defaultAzureCredentialOptions.ExcludeManagedIdentityCredential = false;
defaultAzureCredentialOptions.ExcludeSharedTokenCacheCredential = true;
defaultAzureCredentialOptions.ExcludeVisualStudioCodeCredential = true;
defaultAzureCredentialOptions.ExcludeVisualStudioCredential = true;
defaultAzureCredentialOptions.ManagedIdentityClientId = systemAssignedClientId;
var credential = new DefaultAzureCredential(defaultAzureCredentialOptions);
var client = new SecretClient(new Uri(AzureKeyVaultUrl)), credential);
var secret = await client.GetSecretAsync(secretName).ConfigureAwait(false);
actualSecret = secret.Value.Value;
_logger.LogInformation($"FetchSecretValueFromKeyvault: Received secretValue for {secretName}");
}
catch (RequestFailedException ex)
{
actualSecret = string.Empty;
_logger.LogError($"Message: {ex.Message}. \nInnerException:{ex.InnerException}. \nStackTrace: {ex.StackTrace}. \nInnerExceptionMessage:{ex.InnerException?.Message}.");
}
catch (Exception ex)
{
actualSecret = string.Empty;
_logger.LogError($"Message: {ex.Message}. \nInnerException:{ex.InnerException}. \nStackTrace: {ex.StackTrace}. \nInnerExceptionMessage:{ex.InnerException?.Message}.");
}
return actualSecret;
}
local settings & Azure Function App Settings:
"AzureADManagedIdentityClientId": "xxx-123-abc-xyz-567890"
"AzureKeyVaultUrl": "https://keyvaulturl.azurewebsites.net",
Nuget package and its versions:
Azure.Security.KeyVault.Secrets -- 4.3.0
Azure.Extensions.AspNetCore.Configuration.Secrets -- 1.2.2
Azure.Identity -- 1.6.1
Function Runtime Version: .NET Core V3.1
I am trying to read same secret value through code with help of same managed identity, I am getting error ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.' while debugging in local machine. I deployed azure function and in application insights, I am getting No Managed Identity found for specified ClientId/ResourceId/PrincipalId. Status: 400 (Bad Request)
I double cross checked PrincipalId, Its existed in both local seetings , azure function app settings and value is correct.
what am i doing wrong?
Please check :
When deployed to Azure resource that actually supports managed identity, the library automatically uses managed identities for Azure resources
Local machines does not support managed identities for Azure resources.
So in local environment Microsoft.Azure.Services.AppAuthentication library uses the developer credentials.
For local development, AzureServiceTokenProvider tries to fetch tokens first using Visual Studio, and then using Azure command-line interface (CLI), or Azure AD Integrated Authentication.
You can try to use connection string specified in the AzureServicesAuthConnectionString environment variable that can be passed to the AzureServiceTokenProvider .
You can use visual studio or azure cli method to pass to azure service authentication.
Using azure cli , you can create service principal rbac for local testing something like
az ad sp create-for-rbac --name local-sp --skip-assignment.
To use a connection string passed to the AzureServiceTokenProvider in the AzureServicesAuthConnectionString environment variable for Local development which uses AzureCli to get token.
`RunAs=Developer; DeveloperTool=AzureCli`
You may then have to add the service principal localtest-sp in the access control (IAM ) for the required Azure services.
Using the DefaultAzureCredential in Azure.Identity will provide some sort of similar type functionality to AzureServiceTokenProvider in AppAuthentication, where current environment can be changed.
Please check this App Authentication client library for .NET | Microsoft Docs to try for other options using secret or certificate.
Snippets from AppAuthentication
Using AppAuthentication library :
AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider();
var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback));
...
Using Azure.Identity library :
var client = new SecretClient(new Uri("https://keyvaultname.vault.azure.net"), new
DefaultAzureCredential());
var secret = client.GetSecret("secretName").Value;
For Access token retrival
Using AppAuthentication library:
var tokenProvider = new AzureServiceTokenProvider();
var accessToken = await tokenProvider.GetAccessTokenAsync(ResourceId);
Using Azure.Identity library:
var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { ResourceId + "/.default" }) { }
);
Reference :
python - ManagedIdentityCredential authentication unavailable, no managed identity endpoint found - Stack Overflow

Graph API - adding Schema Extension using .Net Core 3.1

I need to add custom claims to my Azure B2C users, so I figured the way to do this is to add schema extensions to the User for my directory App with Graph API (beta).
I wrote a simple test for that:
SchemaExtension schemaExtension = new SchemaExtension
{
Id = schemaName,
Owner = _appClientId.ToString(),
Description = string.IsNullOrWhiteSpace(schemaDesc) ? string.Empty : schemaDesc.Trim(),
TargetTypes = new List<string>
{
"User"
},
Properties = new List<ExtensionSchemaProperty>
{
new ExtensionSchemaProperty
{
Name = "isGlobalAdmin",
Type = "Boolean"
},
new ExtensionSchemaProperty
{
Name = "isOrganizationAdmin",
Type = "Boolean"
}
}
};
SchemaExtension extension = await GraphClient.SchemaExtensions
.Request()
.AddAsync(schemaExtension);
First, it didn't work because of lack of permissions. So I created a new user in my directory and added Global Admin role to it. Then I set Treat application as a public client to true in the app authentication settings. That fixed permission problem.
But now I have this one:
Microsoft.Graph.ServiceException : Code: Service_InternalServerError
I tried changing params for the SchemaExtension but nothing helps.
How can I make this work?
API I use - Microsoft.Graph.Beta
UPDATE - Graph API init
private async Task<GraphServiceClient> InitGraphClientWithUserAndPassword()
{
try
{
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create(_appClientId.ToString())
.WithTenantId(_tenantId.ToString())
.Build();
UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication); // scopes
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
SecureString securePass = new NetworkCredential("", _password).SecurePassword;
User me = await graphClient.Me.Request()
.WithUsernamePassword(_userEmail, securePass)
.GetAsync();
return graphClient;
}
catch (Exception ex)
{
const string ERR_MSG = "Could not create GraphAPI client";
_logger.LogError(ex, ERR_MSG);
throw new IlgGraphApiException(ERR_MSG, ex);
}
}
I have tested your code. It works fine for Azure AD but gets error Code: Service_InternalServerError\r\nMessage: Encountered an internal server error.\r\n\r\nInner error\r\n for Azure AD B2C.
I don't think Microsoft Graph API Create schemaExtension is supported for Azure AD B2C currently.
As this article says, Custom attributes in Azure AD B2C use Azure AD Graph API Directory Schema Extensions. Support for newer Microsoft Graph API for querying Azure AD B2C tenant is still under development.

Could not bootstrap with CCCP : Couchbase memcached bucket exception

I'm using the latest version of CouchbaseNetClient NuGet package 2.7.4 to connect Couchbase 4.6.3 enterprise version(running on docker in my laptop).
C# Code :
var config = new ClientConfiguration
{
// assign one or more Couchbase Server URIs available for bootstrap
Servers = new List<Uri>
{
new Uri("http://192.168.99.100:8091/")
},
BucketConfigs = new Dictionary<string, BucketConfiguration> {
{"memcachetest", new BucketConfiguration {
PoolConfiguration = new PoolConfiguration {
MaxSize = 6,
MinSize = 4,
SendTimeout = 12000
},
Port = 8091,
DefaultOperationLifespan = 123,
Password = "",
Username = "",
BucketName = "memcachetest"
}}},
UseSsl = false,
};
ClusterHelper.Initialize(config);
This code works fine for the normal bucket(sample bucket below) but I'm unable to connect to Memcached(memcachetest) bucket.
Following line throws all sorts of exception while opening the bucket.
private readonly IBucket _bucket = ClusterHelper.GetBucket("memcachetest", "");
I have tried with/without passwords. It's all over my head now from the last 2 days! Any help appriciated!!
Memcached buckets don't support CCCP. The client will first try CCCP and then move to HTTP Streaming when CCCP fails - this gets logged and probably what you stumbled onto. Since it's an AggregateException, it appears that there may be other reasons why its failing - you'll have to look into each exception for the reason. Note you can skip CCCP for Memcached buckets by setting ConfigurationProviders to HttpStreaming:
ClientConfiguration.ConfigurationProviders = ServerConfigurationProviders.HttpStreaming;

Error while uploading the image to Azure Blob from a cordova application

I am trying to upload a blob from Cordova Application and I am getting 404. However, the SAS URL is valid and working fine with a C# Application.
Please find the code below:
var uriWithAccess = URL;
var xhr = new XMLHttpRequest();
xhr.onerror = fail;
xhr.onloadend = uploadCompleted;
xhr.open("POST", uriWithAccess);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('x-ms-blob-content-type','image/jpeg');
xhr.send(requestData);
Any help will be appreciated. I tried with $.ajax as well but it's also giving 404 error.
PS: The code was working perfectly fine but from last few days it started causing the issue.
Thanks,
Mohit Chhabra
Have you configured CORS ? maybe the js request is failing because execution domain is not allowed in azure storage.
<Cors>
<CorsRule>
<AllowedOrigins>http://www.contoso.com, http://www.fabrikam.com</AllowedOrigins>
<AllowedMethods>PUT,GET</AllowedMethods>
<AllowedHeaders>x-ms-meta-data*,x-ms-meta-target*,x-ms-meta-abc</AllowedHeaders>
<ExposedHeaders>x-ms-meta-*</ExposedHeaders>
<MaxAgeInSeconds>200</MaxAgeInSeconds>
</CorsRule>
<Cors>
To set that configuration you can use azure Storage REST API, or more easily you can run a short C# program like this:
private static void InitializeCors()
{
// CORS should be enabled once at service startup
// Given a BlobClient, download the current Service Properties
ServiceProperties blobServiceProperties = BlobClient.GetServiceProperties();
ServiceProperties tableServiceProperties = TableClient.GetServiceProperties();
// Enable and Configure CORS
ConfigureCors(blobServiceProperties);
ConfigureCors(tableServiceProperties);
// Commit the CORS changes into the Service Properties
BlobClient.SetServiceProperties(blobServiceProperties);
TableClient.SetServiceProperties(tableServiceProperties);
}
private static void ConfigureCors(ServiceProperties serviceProperties)
{
serviceProperties.Cors = new CorsProperties();
serviceProperties.Cors.CorsRules.Add(new CorsRule()
{
AllowedHeaders = new List<string>() { "*" },
AllowedMethods = CorsHttpMethods.Put | CorsHttpMethods.Get | CorsHttpMethods.Head | CorsHttpMethods.Post,
AllowedOrigins = new List<string>() { "*" },
ExposedHeaders = new List<string>() { "*" },
MaxAgeInSeconds = 1800 // 30 minutes
});
}
I'm not sure about what host you should use to enable access to a mobile application, but at first you should try with all host.
Access-Control-Allow-Origin: *
AllowedOrigins = new List<string>() { "*" },
You can follow a detailed guide here:
Windows Azure Storage: Introducing CORS

Error when calling any method on Service Management API

I'm looking to start an Azure runbook from a c# application which will be hosted on an Azure web app.
I'm using certificate authentication (in an attempt just to test that I can connect and retrieve some data)
Here's my code so far:
var cert = ConfigurationManager.AppSettings["mgmtCertificate"];
var creds = new Microsoft.Azure.CertificateCloudCredentials("<my-sub-id>",
new X509Certificate2(Convert.FromBase64String(cert)));
var client = new Microsoft.Azure.Management.Automation.AutomationManagementClient(creds, new Uri("https://management.core.windows.net/"));
var content = client.Runbooks.List("<resource-group-id>", "<automation-account-name>");
Every time I run this, no matter what certificate I use I get the same error:
An unhandled exception of type 'Hyak.Common.CloudException' occurred in Microsoft.Threading.Tasks.dll
Additional information: ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
I've tried downloading the settings file which contains the automatically generated management certificate you get when you spin up the Azure account... nothing I do will let me talk to any of the Azure subscription
Am I missing something fundamental here?
Edit: some additional info...
So I decided to create an application and use the JWT authentication method.
I've added an application, given the application permissions to the Azure Service Management API and ensured the user is a co-administrator and I still get the same error, even with the token...
const string tenantId = "xx";
const string clientId = "xx";
var context = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantId));
var user = "<user>";
var pwd = "<pass>";
var userCred = new UserCredential(user, pwd);
var result = context.AcquireToken("https://management.core.windows.net/", clientId, userCred);
var token = result.CreateAuthorizationHeader().Substring("Bearer ".Length); // Token comes back fine and I can inspect and see that it's valid for 1 hour - all looks ok...
var sub = "<subscription-id>";
var creds = new TokenCloudCredentials(sub, token);
var client = new AutomationManagementClient(creds, new Uri("https://management.core.windows.net/"));
var content = client.Runbooks.List("<resource-group>", "<automation-id>");
I've also tried using other Azure libs (like auth, datacentre etc) and I get the same error:
ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription.
I'm sure it's just 1 tickbox I need to tick buried somewhere in that monolithic Management Portal but I've followed a few tutorials on how to do this and they all end up with this error...
public async Task StartAzureRunbook()
{
try
{
var subscriptionId = "azure subscription Id";
string base64cer = "****long string here****"; //taken from http://stackoverflow.com/questions/24999518/azure-api-the-server-failed-to-authenticate-the-request
var cert = new X509Certificate2(Convert.FromBase64String(base64cer));
var client = new Microsoft.Azure.Management.Automation.AutomationManagementClient(new CertificateCloudCredentials(subscriptionId, cert));
var ct = new CancellationToken();
var content = await client.Runbooks.ListByNameAsync("MyAutomationAccountName", "MyRunbookName", ct);
var firstOrDefault = content?.Runbooks.FirstOrDefault();
if (firstOrDefault != null)
{
var operation = client.Runbooks.Start("MyAutomationAccountName", new RunbookStartParameters(firstOrDefault.Id));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Also in portal:
1) Application is multitenant
2) Permissions to other applications section - Windows Azure Service Manager - Delegated permissions "Access Azure Service Management(preview)"
Ensure that your Management certificate has private key and was not made from the .CER file. The fact that you're not supplying a password when generating the X509Certificate object makes me think you're using public key only
Ensure that your Managemnet's certificate public key (.CER file) has been uploaded to the Azure management portal (legacy version, Management Certificate area)
Use CertificateCloudCredentials and not any other credential type of an object
Ok, stupid really but one of the tutorials I followed suggested installing the prerelease version of the libs.
Installing the preview (0.15.2-preview) has fixed the issue!

Categories

Resources