繁体   English   中英

使用Azure活动目录进行身份验证时进行Azure管理库API调用时出错

[英]Error making Azure Management Library API call when authenticating with azure active directory

我的公司正在研究有关Azure的报告。 我们只希望我们的客户给我们只读的凭证供我们使用。 我做了一些研究,看起来Azure Active Directory就是这样做的。 因此,我正在寻找使用只读Azure目录应用程序进行身份验证的方法。

为了让我开始工作,我关注了此博客,介绍如何通过Azure Active Directory使用Management API。

https://msdn.microsoft.com/zh-CN/library/azure/dn722415.aspx

除了方法显示非常不友好之外,它不起作用=(

以全局管理员身份登录后,出现此错误:

“ AADSTS90014:请求正文必须包含以下参数:'client_secret或client_assertion'。”

做了一些研究,发现这种身份验证样式适用于本机应用程序,而不适用于Web应用程序(尽管博客帖子另有说明。)。 所以我做了一个调整。 我的GetAuthorizationHeader现在看起来像这样:

    private static string GetAuthorizationHeader()
    {
        AuthenticationResult result = null;

        var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);

        string clientId = ConfigurationManager.AppSettings["clientId"];
        string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
        ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

        var thread = new Thread(() =>
        {
            result = context.AcquireToken(
              "https://management.core.windows.net/",
              clientCred);
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Name = "AquireTokenThread";
        thread.Start();
        thread.Join();

        if (result == null)
        {
            throw new InvalidOperationException("Failed to obtain the JWT token");
        }

        string token = result.AccessToken;
        return token;
    }

我能够获得访问令牌(是)。 但是现在当我尝试将其与Azure管理库客户端一起使用时,出现此错误:

“ ForbiddenError:服务器未能验证请求。验证证书有效并与此预订关联。”

我仔细检查了我在应用程序中的权限。 看起来不错。 我尝试让所有内容都具有完全访问权限,以查看是否会有所作为。

我仔细检查了我的tenantId,clientId和subscriptionId,它们看起来都不错。

我确保我正在使用的订阅指向我的应用程序所在的广告。

我尝试制作新的密钥。

我的猜测是这是问题所在: 在此处输入图片说明 但是,在此UI中,我无法为该属性选择任何值。 我不确定这是错误还是未完成的结果。 我在这里想念什么吗?

谢谢

这是我的完整代码供参考:

class Program
{
    static void Main(string[] args)
    {
        var token = GetAuthorizationHeader();

        var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);

        using (var computeClient = new ComputeManagementClient(credential))
        {
            var images = computeClient.VirtualMachineOSImages.List();
        }
    }

    private static string GetAuthorizationHeader()
    {
        AuthenticationResult result = null;

        var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);

        string clientId = ConfigurationManager.AppSettings["clientId"];
        string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
        ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

        var thread = new Thread(() =>
        {
            result = context.AcquireToken(
              "https://management.core.windows.net/",
              clientCred);
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Name = "AquireTokenThread";
        thread.Start();
        thread.Join();

        if (result == null)
        {
            throw new InvalidOperationException("Failed to obtain the JWT token");
        }

        string token = result.AccessToken;
        return token;
    }
}

编辑:已取得进展。 正如我与Gaurav讨论的那样,我需要放弃Azure管理库,因为到目前为止,它似乎还不支持Azure资源管理器(ARM)API! 因此,我做了原始的Web请求。 它按预期工作。 如果我从AD应用程序中删除角色访问权限,则访问将被拒绝。 当我拥有它时,我会取回数据。

我不确定要实现的一件事,因此我的应用程序会自动添加到新资源中。

另外,是否可以列出可供我的AD应用程序访问的资源组?

新代码:

    class Program
{
    static void Main(string[] args)
    {
        var token = GetAuthorizationHeader();

        string subscriptionId = ConfigurationManager.AppSettings["subscriptionId"];
        string resourceGroupName = ConfigurationManager.AppSettings["resourceGroupName"];
        var uriListMachines = string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualmachines?api-version=2015-05-01-preview", subscriptionId, resourceGroupName);
        var t = WebRequest.Create(uriListMachines);
        t.ContentType = "application/json";
        t.Headers.Add("Authorization", "Bearer " + token);
        var response = (HttpWebResponse)t.GetResponse();

        string result = "";
        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            result = reader.ReadToEnd(); 
        }

        //Original Attempt:
        //var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);

        //using (var client = CloudContext.Clients.CreateComputeManagementClient(credential))
        //{
        //    var images = client.VirtualMachineVMImages.List();
        //}
    }

    private static string GetAuthorizationHeader()
    {
        AuthenticationResult result = null;

        var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);

        string clientId = ConfigurationManager.AppSettings["clientId"];
        string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
        ClientCredential clientCred = new ClientCredential(clientId, clientSecret);

        var thread = new Thread(() =>
        {
            result = context.AcquireToken(
              "https://management.core.windows.net/",
              clientCred);
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Name = "AquireTokenThread";
        thread.Start();
        thread.Join();

        if (result == null)
        {
            throw new InvalidOperationException("Failed to obtain the JWT token");
        }

        string token = result.AccessToken;
        return token;
    }
}

编辑:我想通了。 在OLD门户中创建的资源将获得它自己的独特资源组。

据我所知,您不能添加在旧门户网站现有资源组(boooo)中创建的资源。 在新门户中创建的资源将能够将资源分配给现有组(也就是可以授予我AD应用程序角色访问权限的组)。

真是一团糟! 但是至少我知道现在发生了什么。

我相信您在遇到这个问题的道路上是正确的。

这是正在发生的事情:

本质上,执行Service Management APIdelegated permission and not an application permissiondelegated permission and not an application permission 换句话说,在为其获取令牌的用户的上下文中执行API。 现在,您正在为您的应用程序获取此令牌(由客户端ID /秘密指定)。 但是,您的应用程序无权访问Azure订阅,因为在Azure AD中为此应用程序创建的用户记录属于Service Principal类型。 由于此服务主体无权访问您的Azure订阅,因此您会收到此“ Forbidden Error (我必须说该错误具有误导性,因为您根本没有使用证书)。

您可以做一些事情:

  1. 切换到Azure资源管理器(ARM)API -ARM API是下一代服务管理API(SM API),Azure仅朝这个方向发展。 它仅适用于Azure AD令牌。 如果可能的话,请利用它来管理您的Azure资源(尽管要记住,到目前为止,并不是所有的Azure资源都可以通过ARM API进行管理)。 他们采用的方法是采用服务主体,然后使用新的Azure Portal将其分配给特定角色。 请参阅此链接以获取有关此内容的更多详细信息: https : //azure.microsoft.com/zh-cn/documentation/articles/resource-group-create-service-principal-portal/
  2. 使用X509证书 -您始终可以使用基于X509证书的授权来授权您的SM API请求。 请参阅此链接以获取有关此内容的更多详细信息: https : //msdn.microsoft.com/zh-cn/library/azure/ee460782.aspx#bk_cert 这种方法的缺点是应用程序(或有权访问此证书的任何人)将获得对您的Azure订阅的完全访问权限,并且可以在其中执行所有操作(包括删除资源)。
  3. 为用户而不是应用程序获取令牌 -这是您可以采用的另一种方法。 本质上是要求您的用户通过控制台应用程序登录到Azure AD,并获取该用户的令牌。 再次提醒您,此用户必须是您的Azure订阅中的Co-Admin ,并且将拥有对您的Azure订阅的完全访问权限,因为使用SM API时,没有Role-based access control概念。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM