Cynek
Cynek

Reputation: 21

Azure Management API Authentication problems using X509Certificate2

I have problem with authorization in azure management API with certificate authorization. When using use Microsoft.Azure.Management.Sql i get error: "AuthenticationFailedInvalidHeader: Authentication failed. The 'Authorization' header is provided in an invalid format." But when I use Microsoft.WindowsAzure.Management.Sql with almost the same code everything works fine, but this is the old version of this library. I need newer version, because old looks like doesn't support elastic pools.

This work just fine

using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Management.Sql;
using Microsoft.WindowsAzure.Management.Sql.Models;

namespace Test2
{
    class Program
    {
        private static ServerListResponse servers;
        private static string _resourceGroupName = "xxx";
        private static string subscriptionId = "xxx";
        private static string certThumbprint = "xxx";

        static void Main(string[] args)
        {
            X509Certificate2 cert = GetCertificate(certThumbprint);

            SubscriptionCloudCredentials credentials = new CertificateCloudCredentials(subscriptionId, cert);
            SqlManagementClient client = new SqlManagementClient(credentials);

            servers = client.Servers.List();

            Console.ReadKey();
        }            
    }
}

This generate error

using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Azure;
using Microsoft.Azure.Management.Sql;
using Microsoft.Azure.Management.Sql.Models;

namespace Test2
{
    class Program
    {
        private static ServerListResponse servers;
        private static string _resourceGroupName = "xxx";
        private static string subscriptionId = "xxx";
        private static string certThumbprint = "xxx";

        static void Main(string[] args)
        {
            X509Certificate2 cert = GetCertificate(certThumbprint);

            SubscriptionCloudCredentials credentials = new CertificateCloudCredentials(subscriptionId, cert);
            SqlManagementClient client = new SqlManagementClient(credentials);

            Task.Run(async () =>
            {
                servers = await client.Servers.ListAsync(_resourceGroupName);
            }).Wait();

            Console.ReadKey();
        }               
    }
}

Upvotes: 2

Views: 1150

Answers (2)

Jack Zeng
Jack Zeng

Reputation: 2267

For Microsoft.Azure, they change the authorization strategy. X509Certificates is no longer supported like that. However, you can use ADAL with an interactive login or a Service Principal.

Here is a sample code:

Interactive login:

using System;
using System.Security;
using Microsoft.Azure.Management.Sql;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure;

namespace GetSqlARM
{
    class Program
    {
        static void Main(string[] args)
        {
            var token = GetTokenCloudCredentials();
            SqlManagementClient client = new SqlManagementClient(token);

            var server = client.Servers.Get("<Your Resource Group>", "<Your Sql Server>");

            System.Console.WriteLine(server.ToString());
            System.Console.WriteLine("Press ENTER to continue");
            System.Console.ReadLine();
        }

        public static TokenCloudCredentials GetTokenCloudCredentials()
        {
            String tenantID = "<Your Tenant ID>";
            String loginEndpoint = "https://login.windows.net/";
            Uri redirectURI = new Uri("urn:ietf:wg:oauth:2.0:oob");
            String clientID = "1950a258-227b-4e31-a9cf-717495945fc2";
            String subscriptionID = "<Your Subscription ID>";
            String resource = "https://management.core.windows.net/";
            String authString = loginEndpoint + tenantID;

            AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);

            var promptBehaviour = PromptBehavior.Auto;

            var userIdentifierType = UserIdentifierType.RequiredDisplayableId;

            var userIdentifier = new UserIdentifier("<Your Azure Account>", userIdentifierType);

            var authenticationResult = authenticationContext.AcquireToken(resource, clientID, redirectURI, promptBehaviour, userIdentifier);

            return new TokenCloudCredentials(subscriptionID, authenticationResult.AccessToken);
        }
    }
}

Service Principal:

Replace the GetTokenCloudCredentials method in the above program by the following.

    public static TokenCloudCredentials GetTokenCloudCredentials()
    {
        String tenantID = "<Your Tenant ID>";
        String loginEndpoint = "https://login.windows.net/";
        String subscriptionID = "<Your Subscription ID>";
        String authString = loginEndpoint + tenantID;
        String clientID = "<Your Client ID>";
        String key = "<Your Client Key>";
        var clientCred = new ClientCredential(clientID, key);
        String resource = "https://management.core.windows.net/";

        AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);

        var authenticationResult = authenticationContext.AcquireToken(resource, clientCred);

        return new TokenCloudCredentials(subscriptionID, authenticationResult.AccessToken);
    }

In order to use the Service Principal Code, you need to follow this article to create a Service Principal.

For those package, I am using the following version:

  • Microsoft.Azure.Management.Sql, v0.46.0-prerelease
  • Microsoft.IdentityModel.Clients.ActiveDirectory, v2.26.305102204
  • Microsoft.Rest.ClientRuntime.Azure, v3.2.0

Upvotes: 1

Trondh
Trondh

Reputation: 3361

The new api uses resource manager, in which the typical scenario is to use a client id /secret or username/password for authentication.

That said, if you want to stick with certificates that's certainly possible, but it does require a bit of work to set up. ARM basically authenticates "thru" an application, and you can configure pki on that application. I wrote about the configuration (using PowerShell but should be transferable) a while back:

http://hindenes.com/trondsworking/2015/07/19/certificate-based-authentication-to-azure-resource-manager-using-powershell/

Upvotes: 0

Related Questions