Refresh SignedJwtAssertionCredentials w/Storage.

Reviewed in http://codereview.appspot.com/6346086/.

Fixes issue #160.
diff --git a/oauth2client/appengine.py b/oauth2client/appengine.py
index b484c1e..ca2ff15 100644
--- a/oauth2client/appengine.py
+++ b/oauth2client/appengine.py
@@ -42,6 +42,9 @@
 from google.appengine.ext.webapp.util import login_required
 from google.appengine.ext.webapp.util import run_wsgi_app
 
+
+logger = logging.getLogger(__name__)
+
 OAUTH2CLIENT_NAMESPACE = 'oauth2client#ns'
 
 
@@ -148,7 +151,7 @@
 
   # For writing to datastore.
   def get_value_for_datastore(self, model_instance):
-    logging.info("get: Got type " + str(type(model_instance)))
+    logger.info("get: Got type " + str(type(model_instance)))
     cred = super(CredentialsProperty,
                  self).get_value_for_datastore(model_instance)
     if cred is None:
@@ -159,7 +162,7 @@
 
   # For reading from datastore.
   def make_value_from_datastore(self, value):
-    logging.info("make: Got type " + str(type(value)))
+    logger.info("make: Got type " + str(type(value)))
     if value is None:
       return None
     if len(value) == 0:
@@ -172,7 +175,7 @@
 
   def validate(self, value):
     value = super(CredentialsProperty, self).validate(value)
-    logging.info("validate: Got type " + str(type(value)))
+    logger.info("validate: Got type " + str(type(value)))
     if value is not None and not isinstance(value, Credentials):
       raise db.BadValueError('Property %s must be convertible '
                           'to a Credentials instance (%s)' %
diff --git a/oauth2client/client.py b/oauth2client/client.py
index a5f2c2d..5ccaccd 100644
--- a/oauth2client/client.py
+++ b/oauth2client/client.py
@@ -788,7 +788,9 @@
         scope = ' '.join(scope)
       self.scope = scope
 
-      self.private_key = private_key
+      # Keep base64 encoded so it can be stored in JSON.
+      self.private_key = base64.b64encode(private_key)
+
       self.private_key_password = private_key_password
       self.service_account_name = service_account_name
       self.kwargs = kwargs
@@ -798,14 +800,15 @@
       data = simplejson.loads(s)
       retval = SignedJwtAssertionCredentials(
           data['service_account_name'],
-          data['private_key'],
-          data['private_key_password'],
+          base64.b64decode(data['private_key']),
           data['scope'],
-          data['user_agent'],
-          data['token_uri'],
-          data['kwargs']
+          private_key_password=data['private_key_password'],
+          user_agent=data['user_agent'],
+          token_uri=data['token_uri'],
+          **data['kwargs']
           )
       retval.invalid = data['invalid']
+      retval.access_token = data['access_token']
       return retval
 
     def _generate_assertion(self):
@@ -821,9 +824,9 @@
       payload.update(self.kwargs)
       logger.debug(str(payload))
 
+      private_key = base64.b64decode(self.private_key)
       return make_signed_jwt(
-          Signer.from_string(self.private_key, self.private_key_password),
-          payload)
+          Signer.from_string(private_key, self.private_key_password), payload)
 
   # Only used in verify_id_token(), which is always calling to the same URI
   # for the certs.
diff --git a/oauth2client/crypt.py b/oauth2client/crypt.py
index 3df861d..4204417 100644
--- a/oauth2client/crypt.py
+++ b/oauth2client/crypt.py
@@ -24,6 +24,8 @@
 from anyjson import simplejson
 
 
+logger = logging.getLogger(__name__)
+
 CLOCK_SKEW_SECS = 300  # 5 minutes in seconds
 AUTH_TOKEN_LIFETIME_SECS = 300  # 5 minutes in seconds
 MAX_TOKEN_LIFETIME_SECS = 86400  # 1 day in seconds
@@ -161,7 +163,7 @@
   signature = signer.sign(signing_input)
   segments.append(_urlsafe_b64encode(signature))
 
-  logging.debug(str(segments))
+  logger.debug(str(segments))
 
   return '.'.join(segments)
 
diff --git a/tests/test_oauth2client_jwt.py b/tests/test_oauth2client_jwt.py
index dcbb33c..65a3410 100644
--- a/tests/test_oauth2client_jwt.py
+++ b/tests/test_oauth2client_jwt.py
@@ -25,6 +25,7 @@
 import httplib2
 import os
 import sys
+import tempfile
 import time
 import unittest
 import urlparse
@@ -37,9 +38,11 @@
 from apiclient.http import HttpMockSequence
 from oauth2client import crypt
 from oauth2client.anyjson import simplejson
+from oauth2client.client import Credentials
 from oauth2client.client import SignedJwtAssertionCredentials
 from oauth2client.client import VerifyJwtTokenError
 from oauth2client.client import verify_id_token
+from oauth2client.file import Storage
 
 
 def datafile(filename):
@@ -182,7 +185,10 @@
     })
     self._check_jwt_failure(jwt, 'Wrong recipient')
 
-  def test_signed_jwt_assertion_credentials(self):
+
+class SignedJwtAssertionCredentialsTests(unittest.TestCase):
+
+  def test_credentials_good(self):
     private_key = datafile('privatekey.p12')
     credentials = SignedJwtAssertionCredentials(
         'some_account@example.com',
@@ -197,5 +203,62 @@
     resp, content = http.request('http://example.org')
     self.assertEqual('Bearer 1/3w', content['Authorization'])
 
+  def test_credentials_to_from_json(self):
+    private_key = datafile('privatekey.p12')
+    credentials = SignedJwtAssertionCredentials(
+        'some_account@example.com',
+        private_key,
+        scope='read+write',
+        prn='joe@example.org')
+    json = credentials.to_json()
+    restored = Credentials.new_from_json(json)
+    self.assertEqual(credentials.private_key, restored.private_key)
+    self.assertEqual(credentials.private_key_password,
+                     restored.private_key_password)
+    self.assertEqual(credentials.kwargs, restored.kwargs)
+
+  def _credentials_refresh(self, credentials):
+    http = HttpMockSequence([
+      ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'),
+      ({'status': '401'}, ''),
+      ({'status': '200'}, '{"access_token":"3/3w","expires_in":3600}'),
+      ({'status': '200'}, 'echo_request_headers'),
+      ])
+    http = credentials.authorize(http)
+    resp, content = http.request('http://example.org')
+    return content
+
+  def test_credentials_refresh_without_storage(self):
+    private_key = datafile('privatekey.p12')
+    credentials = SignedJwtAssertionCredentials(
+        'some_account@example.com',
+        private_key,
+        scope='read+write',
+        prn='joe@example.org')
+
+    content = self._credentials_refresh(credentials)
+
+    self.assertEqual('Bearer 3/3w', content['Authorization'])
+
+  def test_credentials_refresh_with_storage(self):
+    private_key = datafile('privatekey.p12')
+    credentials = SignedJwtAssertionCredentials(
+        'some_account@example.com',
+        private_key,
+        scope='read+write',
+        prn='joe@example.org')
+
+    (filehandle, filename) = tempfile.mkstemp()
+    os.close(filehandle)
+    store = Storage(filename)
+    store.put(credentials)
+    credentials.set_store(store)
+
+    content = self._credentials_refresh(credentials)
+
+    self.assertEqual('Bearer 3/3w', content['Authorization'])
+    os.unlink(filename)
+
+
 if __name__ == '__main__':
   unittest.main()