Make service_account_email public, read-only (#76)

diff --git a/google/auth/app_engine.py b/google/auth/app_engine.py
index d20ddf6..566475e 100644
--- a/google/auth/app_engine.py
+++ b/google/auth/app_engine.py
@@ -87,6 +87,13 @@
         self.token, self.expiry = token, expiry
 
     @property
+    def service_account_email(self):
+        """The service account email."""
+        if self._service_account_id is None:
+            self._service_account_id = app_identity.get_service_account_name()
+        return self._service_account_id
+
+    @property
     def requires_scopes(self):
         """Checks if the credentials requires scopes.
 
diff --git a/google/auth/compute_engine/credentials.py b/google/auth/compute_engine/credentials.py
index cd215c5..5729956 100644
--- a/google/auth/compute_engine/credentials.py
+++ b/google/auth/compute_engine/credentials.py
@@ -93,6 +93,15 @@
             raise exceptions.RefreshError(exc)
 
     @property
+    def service_account_email(self):
+        """The service account email.
+
+        .. note: This is not guaranteed to be set until :meth`refresh` has been
+            called.
+        """
+        return self._service_account_email
+
+    @property
     def requires_scopes(self):
         """False: Compute Engine credentials can not be scoped."""
         return False
diff --git a/google/oauth2/service_account.py b/google/oauth2/service_account.py
index 6159301..24c852b 100644
--- a/google/oauth2/service_account.py
+++ b/google/oauth2/service_account.py
@@ -232,6 +232,11 @@
             subject=self._service_account_email)
 
     @property
+    def service_account_email(self):
+        """The service account email."""
+        return self._service_account_email
+
+    @property
     def requires_scopes(self):
         """Checks if the credentials requires scopes.
 
diff --git a/system_tests/test_compute_engine.py b/system_tests/test_compute_engine.py
index 2d6f42c..e828cff 100644
--- a/system_tests/test_compute_engine.py
+++ b/system_tests/test_compute_engine.py
@@ -32,7 +32,7 @@
     credentials.refresh(http_request)
 
     assert credentials.token is not None
-    assert credentials._service_account_email is not None
+    assert credentials.service_account_email is not None
 
     info = token_info(credentials.token)
     info_scopes = _helpers.string_to_scopes(info['scope'])
diff --git a/system_tests/test_service_account.py b/system_tests/test_service_account.py
index 6b41ca2..aad1497 100644
--- a/system_tests/test_service_account.py
+++ b/system_tests/test_service_account.py
@@ -39,7 +39,7 @@
 
     info = token_info(credentials.token)
 
-    assert info['email'] == credentials._service_account_email
+    assert info['email'] == credentials.service_account_email
     info_scopes = _helpers.string_to_scopes(info['scope'])
     assert set(info_scopes) == set([
         'https://www.googleapis.com/auth/userinfo.email',
diff --git a/tests/compute_engine/test_credentials.py b/tests/compute_engine/test_credentials.py
index daa61fe..87f7472 100644
--- a/tests/compute_engine/test_credentials.py
+++ b/tests/compute_engine/test_credentials.py
@@ -34,6 +34,8 @@
         assert not self.credentials.expired
         # Scopes aren't needed
         assert not self.credentials.requires_scopes
+        # Service account email hasn't been populated
+        assert self.credentials.service_account_email == 'default'
 
     @mock.patch(
         'google.auth._helpers.utcnow', return_value=datetime.datetime.min)
@@ -58,7 +60,7 @@
             datetime.datetime.min + datetime.timedelta(seconds=500))
 
         # Check the credential info
-        assert (self.credentials._service_account_email ==
+        assert (self.credentials.service_account_email ==
                 'service-account@example.com')
         assert self.credentials._scopes == ['one', 'two']
 
diff --git a/tests/oauth2/test_service_account.py b/tests/oauth2/test_service_account.py
index 01234b5..f07f79d 100644
--- a/tests/oauth2/test_service_account.py
+++ b/tests/oauth2/test_service_account.py
@@ -63,7 +63,7 @@
 
         assert (credentials._signer.key_id ==
                 SERVICE_ACCOUNT_INFO['private_key_id'])
-        assert (credentials._service_account_email ==
+        assert (credentials.service_account_email ==
                 SERVICE_ACCOUNT_INFO['client_email'])
         assert credentials._token_uri == SERVICE_ACCOUNT_INFO['token_uri']
 
@@ -77,8 +77,8 @@
             info, scopes=scopes, subject=subject,
             additional_claims=additional_claims)
 
+        assert credentials.service_account_email == info['client_email']
         assert credentials._signer.key_id == info['private_key_id']
-        assert credentials._service_account_email == info['client_email']
         assert credentials._token_uri == info['token_uri']
         assert credentials._scopes == scopes
         assert credentials._subject == subject
@@ -90,8 +90,8 @@
         credentials = service_account.Credentials.from_service_account_file(
             SERVICE_ACCOUNT_JSON_FILE)
 
+        assert credentials.service_account_email == info['client_email']
         assert credentials._signer.key_id == info['private_key_id']
-        assert credentials._service_account_email == info['client_email']
         assert credentials._token_uri == info['token_uri']
 
     def test_from_service_account_file_args(self):
@@ -104,8 +104,8 @@
             SERVICE_ACCOUNT_JSON_FILE, subject=subject,
             scopes=scopes, additional_claims=additional_claims)
 
+        assert credentials.service_account_email == info['client_email']
         assert credentials._signer.key_id == info['private_key_id']
-        assert credentials._service_account_email == info['client_email']
         assert credentials._token_uri == info['token_uri']
         assert credentials._scopes == scopes
         assert credentials._subject == subject
diff --git a/tests/test__oauth2client.py b/tests/test__oauth2client.py
index 9478406..1d7a4a8 100644
--- a/tests/test__oauth2client.py
+++ b/tests/test__oauth2client.py
@@ -54,7 +54,7 @@
     new_credentials = _oauth2client._convert_service_account_credentials(
         old_credentials)
 
-    assert (new_credentials._service_account_email ==
+    assert (new_credentials.service_account_email ==
             old_credentials.service_account_email)
     assert new_credentials._signer.key_id == old_credentials._private_key_id
     assert new_credentials._token_uri == old_credentials.token_uri
@@ -68,7 +68,7 @@
     new_credentials = _oauth2client._convert_service_account_credentials(
         old_credentials)
 
-    assert (new_credentials._service_account_email ==
+    assert (new_credentials.service_account_email ==
             old_credentials.service_account_email)
     assert new_credentials._signer.key_id == old_credentials._private_key_id
     assert new_credentials._token_uri == old_credentials.token_uri
@@ -81,7 +81,7 @@
     new_credentials = _oauth2client._convert_gce_app_assertion_credentials(
         old_credentials)
 
-    assert (new_credentials._service_account_email ==
+    assert (new_credentials.service_account_email ==
             old_credentials.service_account_email)
 
 
diff --git a/tests/test_app_engine.py b/tests/test_app_engine.py
index e1189ed..94f528d 100644
--- a/tests/test_app_engine.py
+++ b/tests/test_app_engine.py
@@ -70,6 +70,23 @@
         assert scoped_credentials.has_scopes(['email'])
         assert not scoped_credentials.requires_scopes
 
+    def test_service_account_email_implicit(self, app_identity_mock):
+        app_identity_mock.get_service_account_name.return_value = (
+            mock.sentinel.service_account_email)
+        credentials = app_engine.Credentials()
+
+        assert (credentials.service_account_email ==
+                mock.sentinel.service_account_email)
+        assert app_identity_mock.get_service_account_name.called
+
+    def test_service_account_email_explicit(self, app_identity_mock):
+        credentials = app_engine.Credentials(
+            service_account_id=mock.sentinel.service_account_email)
+
+        assert (credentials.service_account_email ==
+                mock.sentinel.service_account_email)
+        assert not app_identity_mock.get_service_account_name.called
+
     @mock.patch(
         'google.auth._helpers.utcnow',
         return_value=datetime.datetime.min)