Project create improvements

- Programmatically set Consent (Branding page) saving a user step
- record created_by in client_secrets.json for easier backtracking
- use local project-apis.txt if it exists
This commit is contained in:
Jay Lee
2020-02-13 11:53:51 -05:00
parent a1967bc706
commit bbd4dd736e
3 changed files with 39 additions and 22 deletions

View File

@@ -7391,6 +7391,11 @@ def getCRM2Service(httpc):
discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI) discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI)
def getGAMProjectFile(filepath): def getGAMProjectFile(filepath):
# if file exists locally in GAM path then use it.
# allows for testing changes before updating project.
local_file = os.path.join(GM_Globals[GM_GAM_PATH], filepath)
if os.path.isfile(local_file):
return fileutils.read_file(local_file, continue_on_error=False, display_errors=True)
file_url = GAM_PROJECT_FILEPATH+filepath file_url = GAM_PROJECT_FILEPATH+filepath
httpObj = transport.create_http() httpObj = transport.create_http()
_, c = httpObj.request(file_url, 'GET') _, c = httpObj.request(file_url, 'GET')
@@ -7461,7 +7466,15 @@ def _grantSARotateRights(iam, sa_email):
gapi.call(iam.projects().serviceAccounts(), 'setIamPolicy', resource=f'projects/-/serviceAccounts/{sa_email}', gapi.call(iam.projects().serviceAccounts(), 'setIamPolicy', resource=f'projects/-/serviceAccounts/{sa_email}',
body=body) body=body)
def _createClientSecretsOauth2service(httpObj, projectId): def setGAMProjectConsentScreen(httpObj, projectId, login_hint):
iap = googleapiclient.discovery.build('iap', 'v1',
http=httpObj, cache_discovery=False,
discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI)
body = {'applicationTitle': 'GAM', 'supportEmail': login_hint}
gapi.call(iap.projects().brands(), 'create',
parent=f'projects/{projectId}', body=body)
def _createClientSecretsOauth2service(httpObj, projectId, login_hint):
def _checkClientAndSecret(simplehttp, client_id, client_secret): def _checkClientAndSecret(simplehttp, client_id, client_secret):
url = 'https://oauth2.googleapis.com/token' url = 'https://oauth2.googleapis.com/token'
@@ -7489,8 +7502,9 @@ def _createClientSecretsOauth2service(httpObj, projectId):
print(f'Unknown error: {content}') print(f'Unknown error: {content}')
return False return False
GAMProjectAPIs = getGAMProjectFile('src/project-apis.txt').splitlines() GAMProjectAPIs = getGAMProjectFile('project-apis.txt').splitlines()
enableGAMProjectAPIs(GAMProjectAPIs, httpObj, projectId, False) enableGAMProjectAPIs(GAMProjectAPIs, httpObj, projectId, False)
setGAMProjectConsentScreen(httpObj, projectId, login_hint)
iam = googleapiclient.discovery.build('iam', 'v1', iam = googleapiclient.discovery.build('iam', 'v1',
http=httpObj, cache_discovery=False, http=httpObj, cache_discovery=False,
discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI) discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI)
@@ -7513,16 +7527,16 @@ def _createClientSecretsOauth2service(httpObj, projectId):
client_email=service_account['email'], client_email=service_account['email'],
client_id=service_account['uniqueId']) client_id=service_account['uniqueId'])
_grantSARotateRights(iam, service_account['name'].rsplit('/', 1)[-1]) _grantSARotateRights(iam, service_account['name'].rsplit('/', 1)[-1])
console_credentials_url = f'https://console.developers.google.com/apis/credentials/consent/edit?createClient&newAppInternalUser=true&project={projectId}' console_url = f'https://console.cloud.google.com/apis/credentials/oauthclient?project={projectId}'
while True: while True:
print(f'''Please go to: print(f'''Please go to:
{console_credentials_url} {console_url}
1. Enter "GAM" for "Application name". 1. Choose "Other".
2. Leave other fields blank. Click "Save" button. 2. Enter a desired value for "Name" or leave as is.
3. Choose "Other". Enter a desired value for "Name". Click the blue "Create" button. 3. Click the blue "Create" button.
4. Copy your "client ID" value. 4. Copy the "client ID" value that shows on the next page.
''') ''')
# If you use Firefox to copy the Client ID and Secret, the data has leading and trailing newlines # If you use Firefox to copy the Client ID and Secret, the data has leading and trailing newlines
@@ -7540,17 +7554,18 @@ def _createClientSecretsOauth2service(httpObj, projectId):
if client_valid: if client_valid:
break break
print() print()
cs_data = '''{ cs_data = f'''{{
"installed": { "installed": {{
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth", "auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
"client_id": "%s", "client_id": "{client_id}",
"client_secret": "%s", "client_secret": "{client_secret}",
"project_id": "%s", "created_by": "{login_hint}",
"project_id": "{projectId}",
"redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"], "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"],
"token_uri": "https://oauth2.googleapis.com/token" "token_uri": "https://oauth2.googleapis.com/token"
} }}
}''' % (client_id, client_secret, projectId) }}'''
fileutils.write_file(GC_Values[GC_CLIENT_SECRETS_JSON], cs_data, continue_on_error=False) fileutils.write_file(GC_Values[GC_CLIENT_SECRETS_JSON], cs_data, continue_on_error=False)
print('That\'s it! Your GAM Project is created and ready to use.') print('That\'s it! Your GAM Project is created and ready to use.')
@@ -7649,7 +7664,7 @@ def _getLoginHintProjectId(createCmd):
PROJECTID_FILTER_REQUIRED = 'gam|<ProjectID>|(filter <String>)' PROJECTID_FILTER_REQUIRED = 'gam|<ProjectID>|(filter <String>)'
def convertGCPFolderNameToID(parent, crm2): def convertGCPFolderNameToID(parent, crm2):
# crm2.folders() is broken requiring pageToken, etc in body, not URL. # crm2.folders() is broken requiring pageToken, etc in body, not URL.
# for now just use callGAPI and if user has that many folders they'll # for now just use gapi.get_items and if user has that many folders they'll
# just need to be specific. # just need to be specific.
folders = gapi.get_items(crm2.folders(), 'search', items='folders', folders = gapi.get_items(crm2.folders(), 'search', items='folders',
body={'pageSize': 1000, 'query': f'displayName="{parent}"'}) body={'pageSize': 1000, 'query': f'displayName="{parent}"'})
@@ -7784,16 +7799,16 @@ and accept the Terms of Service (ToS). As soon as you've accepted the ToS popup,
elif 'error' in status: elif 'error' in status:
controlflow.system_error_exit(2, status['error']) controlflow.system_error_exit(2, status['error'])
break break
_createClientSecretsOauth2service(httpObj, projectId) _createClientSecretsOauth2service(httpObj, projectId, login_hint)
def doUseProject(): def doUseProject():
_checkForExistingProjectFiles() _checkForExistingProjectFiles()
_, httpObj, _, projectId, _ = _getLoginHintProjectId(False) _, httpObj, login_hint, projectId, _ = _getLoginHintProjectId(False)
_createClientSecretsOauth2service(httpObj, projectId) _createClientSecretsOauth2service(httpObj, projectId, login_hint)
def doUpdateProjects(): def doUpdateProjects():
_, httpObj, login_hint, projects, _ = _getLoginHintProjects(False) _, httpObj, login_hint, projects, _ = _getLoginHintProjects(False)
GAMProjectAPIs = getGAMProjectFile('src/project-apis.txt').splitlines() GAMProjectAPIs = getGAMProjectFile('project-apis.txt').splitlines()
count = len(projects) count = len(projects)
print(f'User: {login_hint}, Update {count} Projects') print(f'User: {login_hint}, Update {count} Projects')
i = 0 i = 0
@@ -12415,7 +12430,7 @@ def _checkTPMVulnerability(cros):
def _guessAUE(cros, guessedAUEs): def _guessAUE(cros, guessedAUEs):
if not GC_Values.get('CROS_AUE_DATES', None): if not GC_Values.get('CROS_AUE_DATES', None):
GC_Values['CROS_AUE_DATES'] = json.loads(getGAMProjectFile('src/cros-aue-dates.json')) GC_Values['CROS_AUE_DATES'] = json.loads(getGAMProjectFile('cros-aue-dates.json'))
crosModel = cros.get('model') crosModel = cros.get('model')
if crosModel: if crosModel:
if crosModel not in guessedAUEs: if crosModel not in guessedAUEs:

View File

@@ -2,9 +2,11 @@ admin.googleapis.com
alertcenter.googleapis.com alertcenter.googleapis.com
appsactivity.googleapis.com appsactivity.googleapis.com
calendar-json.googleapis.com calendar-json.googleapis.com
chat.googleapis.com
classroom.googleapis.com classroom.googleapis.com
contacts.googleapis.com contacts.googleapis.com
drive.googleapis.com drive.googleapis.com
iap.googleapis.com
gmail.googleapis.com gmail.googleapis.com
groupssettings.googleapis.com groupssettings.googleapis.com
iam.googleapis.com iam.googleapis.com

View File

@@ -18,7 +18,7 @@ GAM_RELEASES = 'https://github.com/jay0lee/GAM/releases'
GAM_WIKI = 'https://github.com/jay0lee/GAM/wiki' GAM_WIKI = 'https://github.com/jay0lee/GAM/wiki'
GAM_ALL_RELEASES = 'https://api.github.com/repos/jay0lee/GAM/releases' GAM_ALL_RELEASES = 'https://api.github.com/repos/jay0lee/GAM/releases'
GAM_LATEST_RELEASE = GAM_ALL_RELEASES+'/latest' GAM_LATEST_RELEASE = GAM_ALL_RELEASES+'/latest'
GAM_PROJECT_FILEPATH = 'https://raw.githubusercontent.com/jay0lee/GAM/master/' GAM_PROJECT_FILEPATH = 'https://raw.githubusercontent.com/jay0lee/GAM/master/src/'
true_values = ['on', 'yes', 'enabled', 'true', '1'] true_values = ['on', 'yes', 'enabled', 'true', '1']
false_values = ['off', 'no', 'disabled', 'false', '0'] false_values = ['off', 'no', 'disabled', 'false', '0']