मैं जीसीपी पर्यावरण के बाहर से पायथन के माध्यम से एक आईएपी-संरक्षित ऐप इंजन मानक ऐप को प्रोग्रामेटिक रूप से एक्सेस करने का प्रयास कर रहा हूं। मैंने यहां डॉक्स में दिखाई गई विधि सहित विभिन्न विधियों का प्रयास किया है: https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python। यहाँ मेरा कोड है:

from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests

def make_iap_request(url, client_id, method='GET', **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if 'timeout' not in kwargs:
        kwargs['timeout'] = 90

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
    print(f'{open_id_connect_token=}')

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method, url,
        headers={'Authorization': 'Bearer {}'.format(
            open_id_connect_token)}, **kwargs)
    print(f'{resp=}')
    if resp.status_code == 403:
        raise Exception('Service account does not have permission to '
                        'access the IAP-protected application.')
    elif resp.status_code != 200:
        raise Exception(
            'Bad response from application: {!r} / {!r} / {!r}'.format(
                resp.status_code, resp.headers, resp.text))
    else:
        return resp.text

if __name__ == '__main__':
    res = make_iap_request(
        'https://MYAPP.ue.r.appspot.com/',
        'Client ID from IAP>App Engine app>Edit OAuth Client>Client ID'
        )
    print(res)

जब मैं इसे स्थानीय रूप से चलाता हूं, तो मेरे पास GOOGLE_APPLICATION_CREDENTIALS पर्यावरण चर एक स्थानीय JSON क्रेडेंशियल फ़ाइल पर सेट होता है जिसमें उस सेवा खाते की कुंजी होती है जिसका मैं उपयोग करना चाहता हूं। मैंने इसे क्लाउड फ़ंक्शंस में चलाने का भी प्रयास किया है, इसलिए यह संभावित रूप से ऐप इंजन डिफ़ॉल्ट सेवा खाता (मुझे लगता है?) लेने के लिए मेटाडेटा सेवा का उपयोग करेगा।

दोनों ही मामलों में, मैं एक टोकन उत्पन्न करने में सक्षम हूं जो मान्य प्रतीत होता है। jwt.io का उपयोग करके, मैं देखता हूं कि इसमें अपेक्षित डेटा है और हस्ताक्षर मान्य है। हालांकि, जब मैं टोकन का उपयोग करके ऐप से अनुरोध करता हूं, तो मुझे हमेशा यह अपवाद मिलता है:

आवेदन से खराब प्रतिक्रिया: 401 / {'एक्स-गूग-आईएपी-जेनरेटेड-प्रतिक्रिया': 'सत्य', 'दिनांक': 'मंगल, 09 फरवरी 2021 19:25:43 जीएमटी', 'सामग्री-प्रकार': 'पाठ /html', 'सर्वर': 'Google फ़्रंटएंड', 'सामग्री-लंबाई': '47', 'Alt-Svc': 'h3-29=":443"; मा=२५९२०००,एच३-टी०५१=":४४३"; मा=२५९२०००,एच३-क्यू०५०=":४४३"; मा=२५९२०००,एच३-क्यू०४६=":४४३"; मा=२५९२०००,एच३-क्यू०४३=":४४३"; मा = २५९२०००, क्विक =": ४४३"; मा = २५९२०००; v="46,43"'} / 'अमान्य जीसीआईपी आईडी टोकन: जेडब्ल्यूटी हस्ताक्षर अमान्य है'

मुझ से ऐसी कौनसी गलती हो जाएगी?

2
rocklobster 9 फरवरी 2021, 23:30
क्या आप एक्सेस टोकन या पहचान टोकन बना रहे हैं? आपके द्वारा लिखे गए कोड के साथ अपना प्रश्न संपादित करें (अतिरिक्त संदर्भों को छोड़कर लिंक ठीक नहीं हैं)। दिखाएं कि आप ऐप इंजन के लिए अनुरोध कैसे कर रहे हैं। युक्तियाँ। IAP को HTTP शीर्षलेख Authorization: Bearer <TOKEN> में एक पहचान टोकन की आवश्यकता है। त्रुटि JWT signature is invalid का मतलब है कि आपको शायद यह त्रुटि हो रही है कि आप अपने API/REST कॉल में टोकन का उपयोग कैसे कर रहे हैं।
 – 
John Hanley
10 फरवरी 2021, 00:00
पोस्टिंग युक्तियों के लिए धन्यवाद, @JohnHanley। मैंने कोड और कुछ अतिरिक्त विवरणों के साथ अपना प्रश्न अपडेट कर लिया है।
 – 
rocklobster
10 फरवरी 2021, 00:33
आपके प्रारंभिक प्रश्न का उत्तर देने के लिए, मैं एक पहचान टोकन उत्पन्न करने का प्रयास कर रहा हूं, लेकिन यह मेरे लिए स्पष्ट नहीं है कि इस परिदृश्य में एक्सेस टोकन कहां चलन में आता है। क्या मुझे एक कदम याद आ रहा है और पहले एक एक्सेस टोकन जेनरेट करने की आवश्यकता है?
 – 
rocklobster
10 फरवरी 2021, 01:12
आपके कोड में इस कथन का आउटपुट क्या है (केवल पहले और अंतिम 10 वर्ण): print(f'{open_id_connect_token=}')? मुझे लगता है कि आप स्ट्रिंग Client ID from IAP>App Engine app>Edit OAuth Client>Client ID को पहचान टोकन में जोड़ रहे हैं। अगर सही है, तो kwargs को headers={'Authorization': 'Bearer {}'.format(open_id_connect_token)}, **kwargs) से हटा दें
 – 
John Hanley
10 फरवरी 2021, 01:23
2
आपके समय और अंतर्दृष्टि दोनों के लिए धन्यवाद। अंततः, @JohnHanley द्वारा पहचाना गया समाधान एक पहचान प्लेटफ़ॉर्म टोकन (cloud.google.com/iap/docs/…)।
 – 
rocklobster
10 फरवरी 2021, 18:05

1 उत्तर

सबसे बढ़िया उत्तर

इस समस्या का समाधान एक पहचान प्लेटफार्म पहचान टोकन के लिए Google पहचान टोकन का आदान-प्रदान करना है।

त्रुटि का कारण Invalid GCIP ID token: JWT signature is invalid एक Google पहचान टोकन का उपयोग करने के कारण होता है जिस पर Google RSA निजी कुंजी द्वारा हस्ताक्षरित किया जाता है, न कि Google पहचान प्लेटफ़ॉर्म RSA निजी कुंजी द्वारा। मैंने त्रुटि संदेश में GCIP को नज़रअंदाज़ कर दिया, जो एक बार यह पुष्टि करने के बाद कि उपयोग में टोकन दूषित नहीं था, मुझे समाधान बता देता।

प्रश्न में, कोड की यह पंक्ति Google पहचान टोकन प्राप्त करती है:

open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

कोड की उपरोक्त पंक्ति के लिए आवश्यक है कि Google क्लाउड एप्लिकेशन डिफ़ॉल्ट क्रेडेंशियल सेटअप हो। उदाहरण: set GOOGLE_APPLICATION_CREDENTIALS=c:\config\service-account.json

अगला कदम इस टोकन को पहचान प्लेटफॉर्म टोकन के लिए एक्सचेंज करना है:

def exchange_google_id_token_for_gcip_id_token(google_open_id_connect_token):
    SIGN_IN_WITH_IDP_API = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp'
    API_KEY = '';

    url = SIGN_IN_WITH_IDP_API + '?key=' + API_KEY;

    data={
        'requestUri': 'http://localhost',
        'returnSecureToken': True,
        'postBody':'id_token=' + google_open_id_connect_token + '&providerId=google.com'}

    try:
        resp = requests.post(url, data)

        res = resp.json()

        if 'error' in res:
            print("Error: {}".format(res['error']['message']))
            exit(1)

        # print(res)

        return res['idToken']
    except Exception as ex:
        print("Exception: {}".format(ex))
        exit(1)

API कुंजी Google क्लाउड कंसोल -> आइडेंटिटी प्लेटफ़ॉर्म में पाई जा सकती है। ऊपर दाईं ओर "एप्लिकेशन सेटअप विवरण"। यह apiKey और authDomain दिखाएगा।

अधिक जानकारी इस लिंक पर मिल सकती है:

किसी पहचान प्लेटफ़ॉर्म टोकन के लिए Google टोकन का आदान-प्रदान करना

4
John Hanley 11 फरवरी 2021, 00:54
समाधान के लिए धन्यवाद! एक काम जो मैंने थोड़ा अलग किया, वह था क्लाउड कंसोल> एपीआई> क्रेडेंशियल्स> एपीआई कीज़ से एक समर्पित एपीआई कुंजी बनाना और फिर इसे केवल आइडेंटिटी टूलकिट एपीआई तक सीमित रखना।
 – 
rocklobster
11 फरवरी 2021, 00:55
- एपीआई कुंजी में प्रतिबंध जोड़ना एक बहुत अच्छा विचार है।
 – 
John Hanley
11 फरवरी 2021, 00:56