如何使用用户默认凭据以编程方式对云身份识别代理(Cloud IAP)安全资源进行身份验证?

时间:2018-03-02 14:48:48

标签: python google-cloud-platform google-cloud-python google-iap

我希望能够以编程方式在开发环境中使用用户默认凭据(即我自己安装并登录了google cloud sdk的笔记本电脑)为iap生成id令牌。

在关注documentation后,我设法使用服务帐户文件生成授权令牌。

在我的个人计算机上使用google.auth.default时,我可以看到google.oauth2.credentials.Credentials类型的凭据有refresh_token。我想用它来生成令牌,因为它是在documentation下的curl完成的 Authenticating from a desktop app -> Accessing the application但我无法使其发挥作用。有人知道是否有办法以这种方式进行身份验证?

2 个答案:

答案 0 :(得分:3)

正如Matthew所说,用于获取刷新令牌的客户端ID项目应该与IAP客户端ID的项目匹配。 Gcloud使用path_to/google-cloud-sdk/lib/googlecloudsdk/api_lib/auth/util.py中定义的客户端ID和密码作为默认凭据(DEFAULT_CREDENTIALS_DEFAULT_CLIENT_IDDEFAULT_CREDENTIALS_DEFAULT_CLIENT_SECRET)。因此,您无法在google.auth.default()更改util.py时使用刷新令牌,因为获取ID令牌的尝试将失败:

{
 "error": "invalid_audience",
 "error_description": "The audience client and the client need to be in the same project."
}

您的选择是:

  1. 根据Matthew的回复/文档获取刷新令牌(缓存它以避免每次都需要进行用户授权)和ID令牌。
  2. 修补程序客户端ID和gcloud util.py中存在的密码(可能会随gcloud更新而更改)。
  3. 两个选项的示例代码:

    import google.auth
    import requests
    import json
    
    from webbrowser import open_new_tab
    from time import sleep
    
    # use gcloud app default credentials if gcloud's util.py is patched
    def id_token_from_default_creds(audience): 
        cred, proj = google.auth.default()
        # data necessary for ID token
        client_id = cred.client_id
        client_secret= cred.client_secret
        refresh_token = str(cred.refresh_token)
        return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)
    
    def id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):
        oauth_token_base_URL = "https://www.googleapis.com/oauth2/v4/token"
        payload = {"client_id": client_id, "client_secret": client_secret,
                    "refresh_token": refresh_token, "grant_type": "refresh_token",
                    "audience": audience}
        res = requests.post(oauth_token_base_URL, data=payload)
        return (str(json.loads(res.text)[u"id_token"]))
    
    # obtain ID token for provided Client ID: get authorization code -> exchange for refresh token -> obtain and return ID token
    def id_token_from_client_id(client_id, client_secret, audience):
        auth_code = get_auth_code(client_id)
        refresh_token = get_refresh_token_from_code(auth_code, client_id, client_secret)
        return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)
    
    def get_auth_code(client_id):
        auth_url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob"%client_id
        open_new_tab(auth_url)
        sleep(1)
        return raw_input("Authorization code: ")
    
    def get_refresh_token_from_code(auth_code, client_id, client_secret):
        oauth_token_base_URL = 'https://www.googleapis.com/oauth2/v4/token'
        payload = {"code": auth_code, "client_id": client_id, "client_secret": client_secret,
                    "redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "grant_type": "authorization_code"}
        res = requests.post(oauth_token_base_URL, data=payload)
        return (str(json.loads(res.text)[u"refresh_token"]))
    
    print("ID token from client ID: %s" % id_token_from_client_id("<Other client ID>", "<Other client secret>", "<IAP Client ID>")) # other client ID should be from the same project as IAP Client ID 
    print("ID token from \"default\" credentials: %s" % id_token_from_default_creds("<IAP Client ID>"))
    

答案 1 :(得分:1)

感谢您指出这一点!如果我们有这样的代码示例,我会喜欢它,但正如您所发现的那样,至少对于Python,我们对服务帐户auth的代码示例不适用于用户帐户。

我对我们的Python客户端库不太熟悉,告诉你他们是否可以帮助你解决这些问题,但是https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_a_desktop_app引导你完成的要点是:

  1. 为您的客户端应用程序创建一个新的客户端ID(与IAP安全的应用程序在同一个项目中),并使用该客户端ID获取刷新令牌。您不能只使用应用程序默认凭据中的刷新令牌,因为它将具有错误的客户端ID和可能的范围。相反,您需要向应用程序添加“gcloud auth login”等功能并保留刷新令牌。

  2. 获得刷新令牌后,当您的客户端应用想要访问IAP应用时:使用您应用的OAuth客户端的客户端ID和密码,刷新令牌和IAP发送到https://www.googleapis.com/oauth2/v4/token客户ID。这将返回一个OpenID Connect令牌,该令牌对IAP进行一小时的身份验证是有效的。

  3. 这至少足以开始吗?