Skip to content

Commit

Permalink
Google auth dependency update (#1434)
Browse files Browse the repository at this point in the history
### Summary

`oauth2client` has been deprecated since 2019. Updating the library we
use to authenticate with Google to the recommended alternative option,
still maintained by Google.

See:
https://google-auth.readthedocs.io/en/master/oauth2client-deprecation.html

### Related issues or links
-

### Checklist

Provide proof that this works (this makes reviews move faster). Please
perform one or more of the following:
- [ ] Update/add unit or integration tests.
- [x] Include a screenshot showing what the graph looked like before and
after your changes.
- [ ] Include console log trace showing what happened before and after
your changes.

Tested by running the gsuite module locally with some internal
credentials. Module found the appropriate creds using the legacy
delegated method and finished without a problem.

![Screenshot 2025-01-02 at 4 38 58 p
m](https://github.com/user-attachments/assets/df669b12-4dc5-44fd-80a2-3fc4aca6c5c9)

![Screenshot 2025-01-02 at 4 39 39 p
m](https://github.com/user-attachments/assets/7c3e6475-e807-4f84-a92f-bc6ff1b9177a)

---------

Signed-off-by: Sergio Franco <[email protected]>
  • Loading branch information
serge-wq authored Jan 2, 2025
1 parent a91c828 commit d126e32
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ build/
generated
dist/
.local
cartography/_version.py
12 changes: 6 additions & 6 deletions cartography/intel/gcp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

import googleapiclient.discovery
import neo4j
from google.auth import default
from google.auth.credentials import Credentials as GoogleCredentials
from google.auth.exceptions import DefaultCredentialsError
from googleapiclient.discovery import Resource
from oauth2client.client import ApplicationDefaultCredentialsError
from oauth2client.client import GoogleCredentials

from cartography.config import Config
from cartography.intel.gcp import compute
Expand Down Expand Up @@ -295,10 +296,9 @@ def get_gcp_credentials() -> GoogleCredentials:
"""
try:
# Explicitly use Application Default Credentials.
# See https://oauth2client.readthedocs.io/en/latest/source/
# oauth2client.client.html#oauth2client.client.OAuth2Credentials
credentials = GoogleCredentials.get_application_default()
except ApplicationDefaultCredentialsError as e:
# See https://google-auth.readthedocs.io/en/master/user-guide.html#application-default-credentials
credentials, project_id = default()
except DefaultCredentialsError as e:
logger.debug("Error occurred calling GoogleCredentials.get_application_default().", exc_info=True)
logger.error(
(
Expand Down
52 changes: 29 additions & 23 deletions cartography/intel/gsuite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
from collections import namedtuple

import googleapiclient.discovery
import httplib2
import neo4j
from google.auth.exceptions import DefaultCredentialsError
from google.auth.transport.requests import Request
from google.oauth2 import credentials
from google.oauth2 import service_account
from google.oauth2.credentials import Credentials as OAuth2Credentials
from google.oauth2.service_account import Credentials as ServiceAccountCredentials
from googleapiclient.discovery import Resource
from oauth2client.client import ApplicationDefaultCredentialsError
from oauth2client.client import GoogleCredentials

from cartography.config import Config
from cartography.intel.gsuite import api
Expand All @@ -26,21 +29,21 @@
Resources = namedtuple('Resources', 'admin')


def _get_admin_resource(credentials: GoogleCredentials) -> Resource:
def _get_admin_resource(credentials: OAuth2Credentials | ServiceAccountCredentials) -> Resource:
"""
Instantiates a Google API resource object to call the Google API.
Used to pull users and groups. See https://developers.google.com/admin-sdk/directory/v1/guides/manage-users
:param credentials: The GoogleCredentials object
:param credentials: The credentials object
:return: An admin api resource object
"""
return googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials, cache_discovery=False)


def _initialize_resources(credentials: GoogleCredentials) -> Resources:
def _initialize_resources(credentials: OAuth2Credentials | ServiceAccountCredentials) -> Resources:
"""
Create namedtuple of all resource objects necessary for Google API data gathering.
:param credentials: The GoogleCredentials object
:param credentials: The credentials object
:return: namedtuple of all resource objects
"""
return Resources(
Expand All @@ -61,14 +64,17 @@ def start_gsuite_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
"UPDATE_TAG": config.update_tag,
}

creds: OAuth2Credentials | ServiceAccountCredentials
if config.gsuite_auth_method == 'delegated': # Legacy delegated method
logger.info('Attempting to authenticate to GSuite using legacy delegated method')
try:
credentials = GoogleCredentials.from_stream(config.gsuite_config)
credentials = credentials.create_scoped(OAUTH_SCOPE)
credentials = credentials.create_delegated(os.environ.get('GSUITE_DELEGATED_ADMIN'))
creds = service_account.Credentials.from_service_account_file(
config.gsuite_config,
scopes=OAUTH_SCOPE,
)
creds = creds.with_subject(os.environ.get('GSUITE_DELEGATED_ADMIN'))

except ApplicationDefaultCredentialsError as e:
except DefaultCredentialsError as e:
logger.error(
(
"Unable to initialize GSuite creds. If you don't have GSuite data or don't want to load "
Expand All @@ -83,18 +89,18 @@ def start_gsuite_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
auth_tokens = json.loads(str(base64.b64decode(config.gsuite_config).decode()))
logger.info('Attempting to authenticate to GSuite using OAuth')
try:
credentials = GoogleCredentials(
None,
auth_tokens['client_id'],
auth_tokens['client_secret'],
auth_tokens['refresh_token'],
None,
auth_tokens['token_uri'],
'Cartography',
creds = credentials.Credentials(
token=None,
client_id=auth_tokens['client_id'],
client_secret=auth_tokens['client_secret'],
refresh_token=auth_tokens['refresh_token'],
expiry=None,
token_uri=auth_tokens['token_uri'],
scopes=OAUTH_SCOPE,
)
credentials.refresh(httplib2.Http())
credentials = credentials.create_scoped(OAUTH_SCOPE)
except ApplicationDefaultCredentialsError as e:
creds.refresh(Request())
creds = creds.create_scoped(OAUTH_SCOPE)
except DefaultCredentialsError as e:
logger.error(
(
"Unable to initialize GSuite creds. If you don't have GSuite data or don't want to load "
Expand All @@ -106,6 +112,6 @@ def start_gsuite_ingestion(neo4j_session: neo4j.Session, config: Config) -> None
)
return

resources = _initialize_resources(credentials)
resources = _initialize_resources(creds)
api.sync_gsuite_users(neo4j_session, resources.admin, config.update_tag, common_job_parameters)
api.sync_gsuite_groups(neo4j_session, resources.admin, config.update_tag, common_job_parameters)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies = [
"neo4j>=4.4.4,<5.0.0",
"policyuniverse>=1.1.0.0",
"google-api-python-client>=1.7.8",
"oauth2client>=4.1.3",
"google-auth>=2.37.0",
"marshmallow>=3.0.0rc7",
"oci>=2.71.0",
"okta<1.0.0",
Expand Down

0 comments on commit d126e32

Please sign in to comment.