Repository: googleapis/google-cloud-python

Issue:
Allow users to specify p12/json credentials file
From the conversation in #621

> What is the process to specify the keyfile path? That is, I know my keys are at "/creds.json" or "/key.p12" (pick whichever you want) and don't want to use the environment variable stuff...
> - @jgeewax

...

> It does not exist ATM.
> - @dhermes

We need to make sure that people can still be explicit. So the goal of this bug is to make sure people can specify a path to either a `.p12` file or a `.json` file with credentials, and use all the services with those credentials...



Discussion:

Resolving patch:
diff --git a/gcloud/credentials.py b/gcloud/credentials.py
--- a/gcloud/credentials.py
+++ b/gcloud/credentials.py
@@ -24,6 +24,7 @@
 from Crypto.PublicKey import RSA
 from Crypto.Signature import PKCS1_v1_5
 from oauth2client import client
+from oauth2client.client import _get_application_default_credential_from_file
 from oauth2client import crypt
 from oauth2client import service_account
 import pytz
@@ -72,8 +73,37 @@ def get_credentials():
     return client.GoogleCredentials.get_application_default()
 
 
+def get_for_service_account_json(json_credentials_path, scope=None):
+    """Gets the credentials for a service account with JSON key.
+
+    :type json_credentials_path: string
+    :param json_credentials_path: The path to a private key file (this file was
+                                  given to you when you created the service
+                                  account). This file must contain a JSON
+                                  object with a private key and other
+                                  credentials information (downloaded from the
+                                  Google APIs console).
+
+    :type scope: string or tuple of string
+    :param scope: The scope against which to authenticate. (Different services
+                  require different scopes, check the documentation for which
+                  scope is required for the different levels of access to any
+                  particular API.)
+
+    :rtype: :class:`oauth2client.client.GoogleCredentials`,
+            :class:`oauth2client.service_account._ServiceAccountCredentials`
+    :returns: New service account or Google (for a user JSON key file)
+              credentials object.
+    """
+    credentials = _get_application_default_credential_from_file(
+        json_credentials_path)
+    if scope is not None:
+        credentials = credentials.create_scoped(scope)
+    return credentials
+
+
 def get_for_service_account_p12(client_email, private_key_path, scope=None):
-    """Gets the credentials for a service account.
+    """Gets the credentials for a service account with PKCS12 / p12 key.
 
     .. note::
       This method is not used by default, instead :func:`get_credentials`


Test patch:
diff --git a/gcloud/test_credentials.py b/gcloud/test_credentials.py
--- a/gcloud/test_credentials.py
+++ b/gcloud/test_credentials.py
@@ -61,6 +61,54 @@ def test_get_for_service_account_p12_w_scope(self):
         self.assertEqual(client._called_with, expected_called_with)
 
 
+class Test_get_for_service_account_json(unittest2.TestCase):
+
+    def _callFUT(self, json_credentials_path, scope=None):
+        from gcloud.credentials import get_for_service_account_json
+        return get_for_service_account_json(json_credentials_path, scope=scope)
+
+    def test_it(self):
+        from gcloud._testing import _Monkey
+        from gcloud import credentials as MUT
+
+        CREDS = _Credentials()
+        _filenames = []
+
+        def get_creds(filename):
+            _filenames.append(filename)
+            return CREDS
+
+        FILENAME = object()
+
+        renames = {'_get_application_default_credential_from_file': get_creds}
+        with _Monkey(MUT, **renames):
+            self._callFUT(FILENAME)
+
+        self.assertEqual(_filenames, [FILENAME])
+        self.assertFalse(hasattr(CREDS, '_scopes'))
+
+    def test_it_with_scope(self):
+        from gcloud._testing import _Monkey
+        from gcloud import credentials as MUT
+
+        CREDS = _Credentials()
+        _filenames = []
+
+        def get_creds(filename):
+            _filenames.append(filename)
+            return CREDS
+
+        FILENAME = object()
+        SCOPE = object()
+
+        renames = {'_get_application_default_credential_from_file': get_creds}
+        with _Monkey(MUT, **renames):
+            self._callFUT(FILENAME, scope=SCOPE)
+
+        self.assertEqual(_filenames, [FILENAME])
+        self.assertEqual(CREDS._scopes, SCOPE)
+
+
 class Test_generate_signed_url(unittest2.TestCase):
 
     def _callFUT(self, *args, **kwargs):