1919import six
2020from six .moves .urllib .parse import urlencode # pylint: disable=F0401
2121
22- try :
23- from OpenSSL import crypto
24- except ImportError : # pragma: NO COVER
25- # pyOpenSSL can't be installed on App Engine, but it will not
26- # be needed there since app_identity is used.
27- crypto = None
28-
2922from oauth2client import client
30- from oauth2client import crypt
31- from oauth2client .service_account import ServiceAccountCredentials
32- try :
33- from oauth2client .contrib .appengine import (
34- AppAssertionCredentials as _GAECreds )
35- except ImportError :
36- class _GAECreds (object ):
37- """Dummy class if not in App Engine environment."""
38-
39- try :
40- from google .appengine .api import app_identity
41- except ImportError :
42- app_identity = None
4323
4424from gcloud ._helpers import UTC
4525from gcloud ._helpers import _NOW
@@ -102,95 +82,10 @@ def get_credentials():
10282 return client .GoogleCredentials .get_application_default ()
10383
10484
105- def _get_pem_key (credentials ):
106- """Gets private key for a PEM payload from a credentials object.
107-
108- :type credentials: :class:`service_account.ServiceAccountCredentials`,
109- :param credentials: The credentials used to create a private key
110- for signing text.
111-
112- :rtype: :class:`OpenSSL.crypto.PKey`
113- :returns: A PKey object used to sign text.
114- :raises: `TypeError` if `credentials` is the wrong type.
115- `EnvironmentError` if `crypto` did not import successfully.
116- """
117- if isinstance (credentials , ServiceAccountCredentials ):
118- if credentials ._private_key_pkcs12 is not None :
119- # Take our PKCS12 (.p12) text and convert to PEM text.
120- pem_text = crypt .pkcs12_key_as_pem (
121- credentials ._private_key_pkcs12 ,
122- credentials ._private_key_password )
123- else :
124- pem_text = credentials ._private_key_pkcs8_pem
125- else :
126- raise TypeError ((credentials ,
127- 'not a valid service account credentials type' ))
128-
129- if crypto is None :
130- raise EnvironmentError (
131- 'pyOpenSSL must be installed to load a private key' )
132- return crypto .load_privatekey (crypto .FILETYPE_PEM , pem_text )
133-
134-
135- def _get_signature_bytes (credentials , string_to_sign ):
136- """Uses crypto attributes of credentials to sign a string/bytes.
137-
138- :type credentials: :class:`service_account.ServiceAccountCredentials`,
139- :class:`_GAECreds`
140- :param credentials: The credentials used for signing text (typically
141- involves the creation of a PKey).
142-
143- :type string_to_sign: string
144- :param string_to_sign: The string to be signed by the credentials.
145-
146- :rtype: bytes
147- :returns: Signed bytes produced by the credentials.
148- :raises: `EnvironmentError` if `crypto` did not import successfully.
149- """
150- if isinstance (credentials , _GAECreds ):
151- _ , signed_bytes = app_identity .sign_blob (string_to_sign )
152- return signed_bytes
153- else :
154- # Sign the string with the PKey.
155- pkey = _get_pem_key (credentials )
156- if not isinstance (string_to_sign , six .binary_type ):
157- string_to_sign = string_to_sign .encode ('utf-8' )
158- if crypto is None :
159- raise EnvironmentError (
160- 'pyOpenSSL must be installed to sign content using a '
161- 'private key' )
162- return crypto .sign (pkey , string_to_sign , 'SHA256' )
163-
164-
165- def _get_service_account_name (credentials ):
166- """Determines service account name from a credentials object.
167-
168- :type credentials: :class:`service_account.ServiceAccountCredentials`,
169- :class:`_GAECreds`
170- :param credentials: The credentials used to determine the service
171- account name.
172-
173- :rtype: string
174- :returns: Service account name associated with the credentials.
175- :raises: :class:`ValueError` if the credentials are not a valid service
176- account type.
177- """
178- service_account_name = None
179- if isinstance (credentials , ServiceAccountCredentials ):
180- service_account_name = credentials .service_account_email
181- elif isinstance (credentials , _GAECreds ):
182- service_account_name = app_identity .get_service_account_name ()
183-
184- if service_account_name is None :
185- raise ValueError ('Service account name could not be determined '
186- 'from credentials' )
187- return service_account_name
188-
189-
19085def _get_signed_query_params (credentials , expiration , string_to_sign ):
19186 """Gets query parameters for creating a signed URL.
19287
193- :type credentials: :class:`service_account.ServiceAccountCredentials `
88+ :type credentials: :class:`oauth2client.client.AssertionCredentials `
19489 :param credentials: The credentials used to create a private key
19590 for signing text.
19691
@@ -204,9 +99,9 @@ def _get_signed_query_params(credentials, expiration, string_to_sign):
20499 :returns: Query parameters matching the signing credentials with a
205100 signed payload.
206101 """
207- signature_bytes = _get_signature_bytes ( credentials , string_to_sign )
102+ _ , signature_bytes = credentials . sign_blob ( string_to_sign )
208103 signature = base64 .b64encode (signature_bytes )
209- service_account_name = _get_service_account_name ( credentials )
104+ service_account_name = credentials . service_account_email
210105 return {
211106 'GoogleAccessId' : service_account_name ,
212107 'Expires' : str (expiration ),
@@ -246,6 +141,15 @@ def generate_signed_url(credentials, resource, expiration,
246141 response_disposition = None , generation = None ):
247142 """Generate signed URL to provide query-string auth'n to a resource.
248143
144+ .. note::
145+
146+ Assumes ``credentials`` implements a ``sign_blob()`` method that takes
147+ bytes to sign and returns a pair of the key ID (unused here) and the
148+ signed bytes (this is abstract in the base class
149+ :class:`oauth2client.client.AssertionCredentials`). Also assumes
150+ ``credentials`` has a ``service_account_email`` property which
151+ identifies the credentials.
152+
249153 .. note::
250154
251155 If you are on Google Compute Engine, you can't generate a signed URL.
0 commit comments