gam7 7.18.4__py3-none-any.whl → 7.18.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gam7 might be problematic. Click here for more details.

gam/__init__.py CHANGED
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
25
25
  """
26
26
 
27
27
  __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
28
- __version__ = '7.18.04'
28
+ __version__ = '7.18.06'
29
29
  __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
30
30
 
31
31
  #pylint: disable=wrong-import-position
@@ -3952,14 +3952,20 @@ def SetGlobalVariables():
3952
3952
  if checkArgumentPresent(Cmd.SELECT_CMD):
3953
3953
  sectionName = _selectSection()
3954
3954
  GM.Globals[GM.SECTION] = sectionName # Save section for inner gams
3955
- while Cmd.ArgumentsRemaining():
3956
- if checkArgumentPresent('save'):
3957
- GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3958
- _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3959
- elif checkArgumentPresent('verify'):
3960
- _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName)
3961
- else:
3962
- break
3955
+ # If command line is simply: gam select <SectionName>
3956
+ # assume save
3957
+ if not Cmd.ArgumentsRemaining():
3958
+ GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3959
+ _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3960
+ else:
3961
+ while Cmd.ArgumentsRemaining():
3962
+ if checkArgumentPresent('save'):
3963
+ GM.Globals[GM.PARSER].set(configparser.DEFAULTSECT, GC.SECTION, sectionName)
3964
+ _writeGamCfgFile(GM.Globals[GM.PARSER], GM.Globals[GM.GAM_CFG_FILE], Act.SAVE)
3965
+ elif checkArgumentPresent('verify'):
3966
+ _verifyValues(sectionName, inputFilterSectionName, outputFilterSectionName)
3967
+ else:
3968
+ break
3963
3969
  GM.Globals[GM.GAM_CFG_SECTION_NAME] = sectionName
3964
3970
  # showsections
3965
3971
  if checkArgumentPresent(Cmd.SHOWSECTIONS_CMD):
@@ -11482,13 +11488,14 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
11482
11488
  iam = getAPIService(API.IAM, httpObj)
11483
11489
  try:
11484
11490
  service_account = callGAPI(iam.projects().serviceAccounts(), 'create',
11485
- throwReasons=[GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED, GAPI.ALREADY_EXISTS],
11491
+ throwReasons=[GAPI.FAILED_PRECONDITION, GAPI.NOT_FOUND,
11492
+ GAPI.PERMISSION_DENIED, GAPI.ALREADY_EXISTS],
11486
11493
  name=f'projects/{projectInfo["projectId"]}',
11487
11494
  body={'accountId': svcAcctInfo['name'],
11488
11495
  'serviceAccount': {'displayName': svcAcctInfo['displayName'],
11489
11496
  'description': svcAcctInfo['description']}})
11490
11497
  entityActionPerformed([Ent.PROJECT, projectInfo['projectId'], Ent.SVCACCT, service_account['name'].rsplit('/', 1)[-1]])
11491
- except (GAPI.notFound, GAPI.permissionDenied) as e:
11498
+ except (GAPI.failedPrecondition, GAPI.notFound, GAPI.permissionDenied) as e:
11492
11499
  entityActionFailedWarning([Ent.PROJECT, projectInfo['projectId']], str(e))
11493
11500
  return False
11494
11501
  except GAPI.alreadyExists as e:
@@ -44894,21 +44901,44 @@ def waitForMailbox(entityList):
44894
44901
  Ind.Decrement()
44895
44902
 
44896
44903
  def getUserLicenses(lic, user, skus):
44897
- def _callbackGetLicense(_, response, exception):
44904
+ def _callbackGetLicense(request_id, response, exception):
44898
44905
  if exception is None:
44899
44906
  if response and 'skuId' in response:
44900
44907
  licenses.append(response['skuId'])
44908
+ del sku_calls[request_id]
44909
+ else:
44910
+ _, reason, _ = checkGAPIError(exception, softErrors=True)
44911
+ reasons_to_quit = [
44912
+ GAPI.ACCESS_NOT_CONFIGURED, # license API not turned on
44913
+ GAPI.PERMISSION_DENIED, # Admin doesn't have rights to license assignments
44914
+ GAPI.NOT_FOUND # API call succeeded, user does not have this license
44915
+ ]
44916
+ if reason in reasons_to_quit:
44917
+ del sku_calls[request_id]
44901
44918
 
44902
44919
  licenses = []
44903
44920
  svcargs = dict([('userId', user['primaryEmail']), ('productId', None), ('skuId', None), ('fields', 'skuId')]+GM.Globals[GM.EXTRA_ARGS_LIST])
44904
44921
  method = getattr(lic.licenseAssignments(), 'get')
44905
44922
  dbatch = lic.new_batch_http_request(callback=_callbackGetLicense)
44923
+ sku_calls = {}
44906
44924
  for sku in skus:
44907
44925
  svcparms = svcargs.copy()
44908
44926
  svcparms['productId'] = sku[0]
44909
- svcparms['skuId'] = sku[1]
44910
- dbatch.add(method(**svcparms))
44911
- dbatch.execute()
44927
+ sku_id = sku[1]
44928
+ svcparms['skuId'] = sku_id
44929
+ sku_calls[sku_id] = method(**svcparms)
44930
+ try_count = 0
44931
+ while sku_calls:
44932
+ try_count += 1
44933
+ dbatch = lic.new_batch_http_request(callback=_callbackGetLicense)
44934
+ for sku_id, sku_call in sku_calls.items():
44935
+ dbatch.add(sku_call, request_id=sku_id)
44936
+ dbatch.execute()
44937
+ if sku_calls:
44938
+ if try_count >= 5:
44939
+ # give up and return what we have
44940
+ return licenses
44941
+ time.sleep(5)
44912
44942
  return licenses
44913
44943
 
44914
44944
  USER_NAME_PROPERTY_PRINT_ORDER = [
@@ -46393,9 +46423,30 @@ def checkCIUserIsInvitable(users):
46393
46423
  return
46394
46424
  csvPF.writeCSVfile('Invitable Users')
46395
46425
 
46426
+ INBOUNDSSO_INPUT_MODE_CHOICE_MAP = {
46427
+ 'saml': 'saml',
46428
+ 'samlsso': 'saml',
46429
+ 'oidc': 'oidc',
46430
+ 'oidcsso': 'oidc',
46431
+ }
46432
+
46433
+ INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP = {
46434
+ 'all': 'all',
46435
+ 'saml': 'saml',
46436
+ 'samlsso': 'saml',
46437
+ 'oidc': 'oidc',
46438
+ 'oidcsso': 'oidc',
46439
+ }
46440
+
46441
+ INBOUNDSSO_ALL_SAML = {'all', 'saml'}
46442
+ INBOUNDSSO_ALL_OIDC = {'all', 'oidc'}
46443
+
46396
46444
  INBOUNDSSO_MODE_CHOICE_MAP = {
46397
46445
  'ssooff': 'SSO_OFF',
46446
+ 'saml': 'SAML_SSO',
46398
46447
  'samlsso': 'SAML_SSO',
46448
+ 'oidc': 'OIDC_SSO',
46449
+ 'oidcsso': 'OIDC_SSO',
46399
46450
  'domainwidesamlifenabled': 'DOMAIN_WIDE_SAML_IF_ENABLED'
46400
46451
  }
46401
46452
 
@@ -46405,29 +46456,49 @@ def getCIOrgunitID(cd, orgunit):
46405
46456
  ou_id = ou_id[3:]
46406
46457
  return f'orgUnits/{ou_id}'
46407
46458
 
46408
- def _getInboundSSOProfiles(ci):
46459
+ def _getInboundSSOProfiles(ci, mode):
46409
46460
  customer = normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID])
46410
- try:
46411
- return callGAPIpages(ci.inboundSamlSsoProfiles(), 'list', 'inboundSamlSsoProfiles',
46412
- throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46413
- retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46414
- bailOnInternalError=True,
46415
- filter=f'customer=="{customer}"')
46416
- except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46417
- GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46418
- GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46419
- entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46420
- return []
46461
+ profiles = []
46462
+ if mode in INBOUNDSSO_ALL_SAML:
46463
+ try:
46464
+ profiles.extend(callGAPIpages(ci.inboundSamlSsoProfiles(), 'list', 'inboundSamlSsoProfiles',
46465
+ throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46466
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46467
+ bailOnInternalError=True,
46468
+ filter=f'customer=="{customer}"'))
46469
+ except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46470
+ GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46471
+ GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46472
+ entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46473
+ if mode in INBOUNDSSO_ALL_OIDC:
46474
+ try:
46475
+ profiles.extend(callGAPIpages(ci.inboundOidcSsoProfiles(), 'list', 'inboundOidcSsoProfiles',
46476
+ throwReasons=GAPI.CISSO_LIST_THROW_REASONS,
46477
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46478
+ bailOnInternalError=True,
46479
+ filter=f'customer=="{customer}"'))
46480
+ except (GAPI.notFound, GAPI.domainNotFound, GAPI.domainCannotUseApis,
46481
+ GAPI.forbidden, GAPI.badRequest, GAPI.invalid,
46482
+ GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46483
+ entityActionFailedWarning([Ent.INBOUND_SSO_PROFILE, customer], str(e))
46484
+ return profiles
46421
46485
 
46422
- def _convertInboundSSOProfileDisplaynameToName(ci=None, displayName=''):
46486
+ def _convertInboundSSOProfileDisplaynameToName(ci, mode, displayName='',
46487
+ entityType=Ent.INBOUND_SSO_PROFILE):
46423
46488
  if displayName.lower().startswith('id:') or displayName.lower().startswith('uid:'):
46424
46489
  displayName = displayName.split(':', 1)[1]
46425
- if not displayName.startswith('inboundSamlSsoProfiles/'):
46426
- displayName = f'inboundSamlSsoProfiles/{displayName}'
46490
+ if mode == 'all':
46491
+ if not (displayName.startswith('inboundSamlSsoProfiles/') and
46492
+ displayName.startswith('inboundOidcSsoProfiles/')):
46493
+ displayName = f'inboundSamlSsoProfiles/{displayName}'
46494
+ elif mode == 'saml':
46495
+ if not displayName.startswith('inboundSamlSsoProfiles/'):
46496
+ displayName = f'inboundSamlSsoProfiles/{displayName}'
46497
+ else:
46498
+ if not displayName.startswith('inboundOidcSsoProfiles/'):
46499
+ displayName = f'inboundOidcSsoProfiles/{displayName}'
46427
46500
  return displayName
46428
- if not ci:
46429
- ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46430
- profiles = _getInboundSSOProfiles(ci)
46501
+ profiles = _getInboundSSOProfiles(ci, mode)
46431
46502
  matches = []
46432
46503
  for profile in profiles:
46433
46504
  if displayName.lower() == profile.get('displayName', '').lower():
@@ -46435,30 +46506,50 @@ def _convertInboundSSOProfileDisplaynameToName(ci=None, displayName=''):
46435
46506
  if len(matches) == 1:
46436
46507
  return matches[0]['name']
46437
46508
  if len(matches) == 0:
46438
- usageErrorExit(Msg.NO_SSO_PROFILE_MATCHES.format(displayName))
46439
- errMsg = Msg.MULTIPLE_SSO_PROFILES_MATCH.format(displayName)
46440
- for m in matches:
46441
- errMsg += f' {m["name"]} {m["displayName"]}\n'
46442
- usageErrorExit(errMsg)
46509
+ errMsg = Msg.NO_SSO_PROFILE_MATCHES.format(displayName)
46510
+ else:
46511
+ errMsg = Msg.MULTIPLE_SSO_PROFILES_MATCH.format(displayName)
46512
+ for m in matches:
46513
+ errMsg += f' {m["name"]} {m["displayName"]}\n'
46514
+ entityActionFailedWarning([entityType, None], errMsg)
46515
+ return None
46443
46516
 
46444
- def _getInboundSSOProfileArguments(body):
46517
+ def _getInboundSSOProfileArguments(body, mode):
46445
46518
  returnNameOnly = False
46446
- while Cmd.ArgumentsRemaining():
46447
- myarg = getArgument()
46448
- if myarg == 'name':
46449
- body['displayName'] = getString(Cmd.OB_STRING)
46450
- elif myarg == 'entityid':
46451
- body.setdefault('idpConfig', {})['entityId'] = getString(Cmd.OB_STRING)
46452
- elif myarg == 'loginurl':
46453
- body.setdefault('idpConfig', {})['singleSignOnServiceUri'] = getString(Cmd.OB_STRING)
46454
- elif myarg == 'logouturl':
46455
- body.setdefault('idpConfig', {})['logoutRedirectUri'] = getString(Cmd.OB_STRING)
46456
- elif myarg == 'changepasswordurl':
46457
- body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46458
- elif myarg == 'returnnameonly':
46459
- returnNameOnly = True
46460
- else:
46461
- unknownArgumentExit()
46519
+ if mode == 'saml':
46520
+ while Cmd.ArgumentsRemaining():
46521
+ myarg = getArgument()
46522
+ if myarg == 'name':
46523
+ body['displayName'] = getString(Cmd.OB_STRING)
46524
+ elif myarg == 'entityid':
46525
+ body.setdefault('idpConfig', {})['entityId'] = getString(Cmd.OB_STRING)
46526
+ elif myarg == 'loginurl':
46527
+ body.setdefault('idpConfig', {})['singleSignOnServiceUri'] = getString(Cmd.OB_STRING)
46528
+ elif myarg == 'logouturl':
46529
+ body.setdefault('idpConfig', {})['logoutRedirectUri'] = getString(Cmd.OB_STRING)
46530
+ elif myarg == 'changepasswordurl':
46531
+ body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46532
+ elif myarg == 'returnnameonly':
46533
+ returnNameOnly = True
46534
+ else:
46535
+ unknownArgumentExit()
46536
+ else:
46537
+ while Cmd.ArgumentsRemaining():
46538
+ myarg = getArgument()
46539
+ if myarg == 'name':
46540
+ body['displayName'] = getString(Cmd.OB_STRING)
46541
+ elif myarg == 'issueruri':
46542
+ body.setdefault('idpConfig', {})['issuerUri'] = getString(Cmd.OB_STRING)
46543
+ elif myarg == 'changepasswordurl':
46544
+ body.setdefault('idpConfig', {})['changePasswordUri'] = getString(Cmd.OB_STRING)
46545
+ elif myarg == 'clientid':
46546
+ body.setdefault('rpConfig', {})['clientId'] = getString(Cmd.OB_STRING)
46547
+ elif myarg == 'clientsecret':
46548
+ body.setdefault('rpConfig', {})['clientSecret'] = getString(Cmd.OB_STRING)
46549
+ elif myarg == 'returnnameonly':
46550
+ returnNameOnly = True
46551
+ else:
46552
+ unknownArgumentExit()
46462
46553
  return (returnNameOnly, body)
46463
46554
 
46464
46555
  def _showInboundSSOProfile(profile, FJQC, i=0, count=0):
@@ -46489,18 +46580,24 @@ def _processInboundSSOProfileResult(result, returnNameOnly, kvlist, function):
46489
46580
  else:
46490
46581
  writeStdout('inProgress\n')
46491
46582
 
46492
- # gam create inboundssoprofile [name <SSOProfileName>]
46583
+ def _getInboundSSOModeService(ci):
46584
+ mode = getChoice(INBOUNDSSO_INPUT_MODE_CHOICE_MAP, defaultChoice='saml', mapChoice=True)
46585
+ service = ci.inboundSamlSsoProfiles() if mode == 'saml' else ci.inboundOidcSsoProfiles()
46586
+ return (mode, service)
46587
+
46588
+ # gam create inboundssoprofile [saml|oidc] [name <SSOProfileName>]
46493
46589
  # [entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
46494
46590
  # [returnnameonly]
46495
46591
  def doCreateInboundSSOProfile():
46496
46592
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46593
+ mode, service = _getInboundSSOModeService(ci)
46497
46594
  body = {'customer': normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID]),
46498
46595
  'displayName': 'SSO Profile'
46499
46596
  }
46500
- returnNameOnly, body = _getInboundSSOProfileArguments(body)
46597
+ returnNameOnly, body = _getInboundSSOProfileArguments(body, mode)
46501
46598
  kvlist = [Ent.INBOUND_SSO_PROFILE, body['displayName']]
46502
46599
  try:
46503
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'create',
46600
+ result = callGAPI(service, 'create',
46504
46601
  throwReasons=GAPI.CISSO_CREATE_THROW_REASONS,
46505
46602
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46506
46603
  bailOnInternalError=True,
@@ -46511,16 +46608,19 @@ def doCreateInboundSSOProfile():
46511
46608
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46512
46609
  entityActionFailedWarning(kvlist, str(e))
46513
46610
 
46514
- # gam update inboundssoprofile <SSOProfileItem>
46611
+ # gam update inboundssoprofile [saml|oidc] <SSOProfileItem>
46515
46612
  # [entityid <String>] [loginurl <URL>] [logouturl <URL>] [changepasswordurl <URL>]
46516
46613
  # [returnnameonly]
46517
46614
  def doUpdateInboundSSOProfile():
46518
46615
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46519
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46520
- returnNameOnly, body = _getInboundSSOProfileArguments({})
46616
+ mode, service = _getInboundSSOModeService(ci)
46617
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, getString(Cmd.OB_STRING))
46618
+ if not name:
46619
+ return
46620
+ returnNameOnly, body = _getInboundSSOProfileArguments({}, mode)
46521
46621
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46522
46622
  try:
46523
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'patch',
46623
+ result = callGAPI(service, 'patch',
46524
46624
  throwReasons=GAPI.CISSO_UPDATE_THROW_REASONS,
46525
46625
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46526
46626
  bailOnInternalError=True,
@@ -46533,14 +46633,17 @@ def doUpdateInboundSSOProfile():
46533
46633
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46534
46634
  entityActionFailedWarning(kvlist, str(e))
46535
46635
 
46536
- # gam delete inboundssoprofile <SSOProfileItem>
46636
+ # gam delete inboundssoprofile [saml|oidc] <SSOProfileItem>
46537
46637
  def doDeleteInboundSSOProfile():
46538
46638
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46539
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46639
+ mode, service = _getInboundSSOModeService(ci)
46640
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, getString(Cmd.OB_STRING))
46641
+ if not name:
46642
+ return
46540
46643
  checkForExtraneousArguments()
46541
46644
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46542
46645
  try:
46543
- result = callGAPI(ci.inboundSamlSsoProfiles(), 'delete',
46646
+ result = callGAPI(service, 'delete',
46544
46647
  throwReasons=GAPI.CISSO_UPDATE_THROW_REASONS,
46545
46648
  retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46546
46649
  bailOnInternalError=True,
@@ -46553,33 +46656,54 @@ def doDeleteInboundSSOProfile():
46553
46656
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46554
46657
  entityActionFailedWarning(kvlist, str(e))
46555
46658
 
46556
- def _getInboundSSOProfile(ci, name):
46659
+ def _getInboundSSOProfileByName(ci, mode, name):
46660
+ notFound = False
46557
46661
  kvlist = [Ent.INBOUND_SSO_PROFILE, name]
46558
- try:
46559
- return callGAPI(ci.inboundSamlSsoProfiles(), 'get',
46560
- throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46561
- retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46562
- bailOnInternalError=True,
46563
- name=name)
46564
- except GAPI.notFound:
46662
+ if mode in INBOUNDSSO_ALL_SAML:
46663
+ try:
46664
+ return callGAPI(ci.inboundSamlSsoProfiles(), 'get',
46665
+ throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46666
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46667
+ bailOnInternalError=True,
46668
+ name=name)
46669
+ except GAPI.notFound:
46670
+ notFound = True
46671
+ except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46672
+ GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46673
+ entityActionFailedWarning(kvlist, str(e))
46674
+ if mode in INBOUNDSSO_ALL_OIDC:
46675
+ try:
46676
+ return callGAPI(ci.inboundOidcSsoProfiles(), 'get',
46677
+ throwReasons=GAPI.CISSO_GET_THROW_REASONS,
46678
+ retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
46679
+ bailOnInternalError=True,
46680
+ name=name)
46681
+ except GAPI.notFound:
46682
+ notFound = True
46683
+ except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46684
+ GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46685
+ entityActionFailedWarning(kvlist, str(e))
46686
+ if notFound:
46565
46687
  entityActionFailedWarning(kvlist, Msg.DOES_NOT_EXIST)
46566
- except (GAPI.domainNotFound, GAPI.domainCannotUseApis, GAPI.forbidden,
46567
- GAPI.badRequest, GAPI.invalid, GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46568
- entityActionFailedWarning(kvlist, str(e))
46569
46688
  return None
46570
46689
 
46571
- # gam info inboundssoprofile <SSOProfileItem> [formatjson]
46690
+ # gam info inboundssoprofile [all|saml|oidc] <SSOProfileItem> [formatjson]
46572
46691
  def doInfoInboundSSOProfile():
46573
46692
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46574
- name = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46693
+ mode = getChoice(INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP, defaultChoice='all', mapChoice=True)
46694
+ name = getString(Cmd.OB_STRING)
46575
46695
  FJQC = FormatJSONQuoteChar(formatJSONOnly=True)
46576
- profile = _getInboundSSOProfile(ci, name)
46696
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, name)
46697
+ if not name:
46698
+ return
46699
+ mode = 'saml' if name.startswith('inboundSamlSsoProfiles/') else 'oidc'
46700
+ profile = _getInboundSSOProfileByName(ci, mode, name)
46577
46701
  if profile:
46578
46702
  _showInboundSSOProfile(profile, FJQC)
46579
46703
 
46580
- # gam show inboundssoprofile
46704
+ # gam show inboundssoprofile [all|saml|oidc]
46581
46705
  # [formatjson]
46582
- # gam print inboundssoprofile [todrive <ToDriveAttribute>*]
46706
+ # gam print inboundssoprofile [all|saml|oidc] [todrive <ToDriveAttribute>*]
46583
46707
  # [[formatjson [quotechar <Character>]]
46584
46708
  def doPrintShowInboundSSOProfiles():
46585
46709
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
@@ -46587,6 +46711,7 @@ def doPrintShowInboundSSOProfiles():
46587
46711
  csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None
46588
46712
  FJQC = FormatJSONQuoteChar(csvPF)
46589
46713
  cfilter = f'customer=="{customer}"'
46714
+ mode = getChoice(INBOUNDSSO_OUTPUT_MODE_CHOICE_MAP, defaultChoice='all', mapChoice=True)
46590
46715
  while Cmd.ArgumentsRemaining():
46591
46716
  myarg = getArgument()
46592
46717
  if csvPF and myarg == 'todrive':
@@ -46595,7 +46720,7 @@ def doPrintShowInboundSSOProfiles():
46595
46720
  FJQC.GetFormatJSONQuoteChar(myarg, True)
46596
46721
  if csvPF:
46597
46722
  printGettingAllAccountEntities(Ent.INBOUND_SSO_PROFILE, cfilter)
46598
- profiles = _getInboundSSOProfiles(ci)
46723
+ profiles = _getInboundSSOProfiles(ci, mode)
46599
46724
  if not csvPF:
46600
46725
  count = len(profiles)
46601
46726
  if not FJQC.formatJSON:
@@ -46665,6 +46790,7 @@ def _processInboundSSOCredentialsResult(result, kvlist, function):
46665
46790
  # (pemfile <FileName>)|(generatekey [keysize 1024|2048|4096]) [replaceolddest]
46666
46791
  def doCreateInboundSSOCredential():
46667
46792
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46793
+ mode = 'saml'
46668
46794
  profile = None
46669
46795
  generateKey = replaceOldest = False
46670
46796
  keySize = 2048
@@ -46672,7 +46798,11 @@ def doCreateInboundSSOCredential():
46672
46798
  while Cmd.ArgumentsRemaining():
46673
46799
  myarg = getArgument()
46674
46800
  if myarg == 'profile':
46675
- profile = _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))
46801
+ profile = _convertInboundSSOProfileDisplaynameToName(ci, mode,
46802
+ getString(Cmd.OB_STRING),
46803
+ Ent.INBOUND_SSO_CREDENTIALS)
46804
+ if not profile:
46805
+ return
46676
46806
  elif myarg == 'pemfile':
46677
46807
  pemData = readFile(getString(Cmd.OB_FILE_NAME))
46678
46808
  elif myarg == 'generatekey':
@@ -46776,15 +46906,24 @@ def doPrintShowInboundSSOCredentials():
46776
46906
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46777
46907
  csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None
46778
46908
  FJQC = FormatJSONQuoteChar(csvPF)
46909
+ mode = 'saml'
46779
46910
  profiles = []
46780
46911
  while Cmd.ArgumentsRemaining():
46781
46912
  myarg = getArgument()
46782
46913
  if myarg in {'profile', 'profiles'}:
46783
- profiles = [_convertInboundSSOProfileDisplaynameToName(ci, profile) for profile in getString(Cmd.OB_STRING_LIST).split(',')]
46914
+ errors = 0
46915
+ for profile in getEntityList(Cmd.OB_STRING_LIST, shlexSplit=True):
46916
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode, profile, Ent.INBOUND_SSO_CREDENTIALS)
46917
+ if name:
46918
+ profiles.append(name)
46919
+ else:
46920
+ errors += 1
46921
+ if errors:
46922
+ return
46784
46923
  else:
46785
46924
  FJQC.GetFormatJSONQuoteChar(myarg, True)
46786
46925
  if not profiles:
46787
- profiles = [p['name'] for p in _getInboundSSOProfiles(ci)]
46926
+ profiles = [p['name'] for p in _getInboundSSOProfiles(ci, mode)]
46788
46927
  count = len(profiles)
46789
46928
  i = 0
46790
46929
  for profile in profiles:
@@ -46877,6 +47016,7 @@ def _getInboundSSOAssignmentByTarget(ci, cd, target):
46877
47016
  usageErrorExit(Msg.NO_SSO_PROFILE_ASSIGNED.format(targetType, target))
46878
47017
 
46879
47018
  def _getInboundSSOAssignmentArguments(ci, cd, body):
47019
+ mode = None
46880
47020
  rank = 0
46881
47021
  while Cmd.ArgumentsRemaining():
46882
47022
  myarg = getArgument()
@@ -46884,9 +47024,19 @@ def _getInboundSSOAssignmentArguments(ci, cd, body):
46884
47024
  rank = getInteger(minVal=1)
46885
47025
  elif myarg == 'mode':
46886
47026
  body['ssoMode'] = getChoice(INBOUNDSSO_MODE_CHOICE_MAP, mapChoice=True)
46887
- elif myarg == 'profile':
46888
- body['samlSsoInfo'] = {'inboundSamlSsoProfile':
46889
- _convertInboundSSOProfileDisplaynameToName(ci, getString(Cmd.OB_STRING))}
47027
+ if body['ssoMode'] == 'SAML_SSO':
47028
+ mode = 'saml'
47029
+ profile = 'inboundSamlSsoProfile'
47030
+ elif body['ssoMode'] == 'OIDC_SSO':
47031
+ mode = 'oidc'
47032
+ profile = 'inboundOidcSsoProfile'
47033
+ elif mode and myarg == 'profile':
47034
+ name = _convertInboundSSOProfileDisplaynameToName(ci, mode,
47035
+ getString(Cmd.OB_STRING),
47036
+ Ent.INBOUND_SSO_ASSIGNMENT)
47037
+ if not name:
47038
+ return None
47039
+ body['samlSsoInfo'] = {profile: name}
46890
47040
  elif myarg == 'neverredirect':
46891
47041
  body['signInBehavior'] = {'redirectCondition': 'NEVER'}
46892
47042
  elif myarg == 'group':
@@ -46897,7 +47047,7 @@ def _getInboundSSOAssignmentArguments(ci, cd, body):
46897
47047
  unknownArgumentExit()
46898
47048
  if 'ssoMode' not in body:
46899
47049
  missingArgumentExit('mode')
46900
- if body['ssoMode'] == 'SAML_SSO' and 'samlSsoInfo' not in body:
47050
+ if mode and 'samlSsoInfo' not in body:
46901
47051
  missingArgumentExit('profile')
46902
47052
  if 'targetGroup' in body:
46903
47053
  if 'targetOrgUnit' in body:
@@ -46935,13 +47085,17 @@ def _processInboundSSOAssignmentResult(result, kvlist, ci, cd, function):
46935
47085
  else:
46936
47086
  entityActionPerformedMessage(kvlist, Msg.ACTION_IN_PROGRESS.format(f'{function} inboundssoassignment'))
46937
47087
 
46938
- # gam create inboundssoassignment (group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
46939
- # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled) [neverredirect]
47088
+ # gam create inboundssoassignment
47089
+ # (group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)
47090
+ # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)|(mode oidc_sso profile <SSOProfileName>}|(mode domain_wide_saml_if_enabled)
47091
+ # [neverredirect]
46940
47092
  def doCreateInboundSSOAssignment():
46941
47093
  cd = buildGAPIObject(API.DIRECTORY)
46942
47094
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
46943
47095
  body = {'customer': normalizeChannelCustomerID(GC.Values[GC.CUSTOMER_ID])}
46944
47096
  body = _getInboundSSOAssignmentArguments(ci, cd, body)
47097
+ if not body:
47098
+ return
46945
47099
  kvlist = [Ent.INBOUND_SSO_ASSIGNMENT, body['customer']]
46946
47100
  try:
46947
47101
  result = callGAPI(ci.inboundSsoAssignments(), 'create',
@@ -46955,8 +47109,10 @@ def doCreateInboundSSOAssignment():
46955
47109
  GAPI.systemError, GAPI.permissionDenied, GAPI.internalError, GAPI.serviceNotAvailable) as e:
46956
47110
  entityActionFailedWarning(kvlist, str(e))
46957
47111
 
46958
- # gam update inboundssoassignment [(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
46959
- # [(mode sso_off)|(mode saml_sso profile <SSOProfileItem>)(mode domain_wide_saml_if_enabled)] [neverredirect]
47112
+ # gam update inboundssoassignment <SSOAssignmentName>
47113
+ # [(group <GroupItem> rank <Number>)|(ou|org|orgunit <OrgUnitItem>)]
47114
+ # (mode sso_off)|(mode saml_sso profile <SSOProfileItem>)|(mode oidc_sso profile <SSOProfileName>}|(mode domain_wide_saml_if_enabled)
47115
+ # [neverredirect]
46960
47116
  def doUpdateInboundSSOAssignment():
46961
47117
  cd = buildGAPIObject(API.DIRECTORY)
46962
47118
  ci = buildGAPIObject(API.CLOUDIDENTITY_INBOUND_SSO)
@@ -47013,14 +47169,20 @@ def doInfoInboundSSOAssignment():
47013
47169
  return
47014
47170
  name = assignment.get('samlSsoInfo', {}).get('inboundSamlSsoProfile')
47015
47171
  if name:
47016
- profile = _getInboundSSOProfile(ci, name)
47172
+ profile = _getInboundSSOProfileByName(ci, 'saml', name)
47017
47173
  if profile:
47018
47174
  assignment['samlSsoInfo']['inboundSamlSsoProfile'] = profile
47175
+ else:
47176
+ name = assignment.get('oidcSsoInfo', {}).get('inboundOidcSsoProfile')
47177
+ if name:
47178
+ profile = _getInboundSSOProfileByName(ci, 'oidc', name)
47179
+ if profile:
47180
+ assignment['oidcSsoInfo']['inboundOidcSsoProfile'] = profile
47019
47181
  _showInboundSSOAssignment(assignment, FJQC, ci, cd)
47020
47182
 
47021
- # gam show inboundssoassignment
47183
+ # gam show inboundssoassignments
47022
47184
  # [formatjson]
47023
- # gam print inboundssoassignment [todrive <ToDriveAttribute>*]
47185
+ # gam print inboundssoassignments [todrive <ToDriveAttribute>*]
47024
47186
  # [[formatjson [quotechar <Character>]]
47025
47187
  def doPrintShowInboundSSOAssignments():
47026
47188
  cd = buildGAPIObject(API.DIRECTORY)
@@ -71135,7 +71297,7 @@ def _processMessagesThreads(users, entityType):
71135
71297
  try:
71136
71298
  callGAPI(gmail.users().messages(), function,
71137
71299
  throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.INVALID_MESSAGE_ID, GAPI.INVALID, GAPI.INVALID_ARGUMENT,
71138
- GAPI.FAILED_PRECONDITION, GAPI.PERMISSION_DENIED],
71300
+ GAPI.FAILED_PRECONDITION, GAPI.PERMISSION_DENIED, GAPI.QUOTA_EXCEEDED],
71139
71301
  userId='me', body=body)
71140
71302
  for messageId in body['ids']:
71141
71303
  mcount += 1
@@ -71145,7 +71307,7 @@ def _processMessagesThreads(users, entityType):
71145
71307
  csvPF.WriteRow({'User': user, entityHeader: messageId, 'action': Act.Performed()})
71146
71308
  except GAPI.serviceNotAvailable:
71147
71309
  mcount += bcount
71148
- except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e:
71310
+ except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.quotaExceeded) as e:
71149
71311
  _processMessageFailed(user, idsList, f'{str(e)} ({mcount+1}-{mcount+bcount}/{jcount})')
71150
71312
  mcount += bcount
71151
71313
  except GAPI.invalidMessageId:
@@ -71158,7 +71320,8 @@ def _processMessagesThreads(users, entityType):
71158
71320
 
71159
71321
  _GMAIL_ERROR_REASON_TO_MESSAGE_MAP = {GAPI.NOT_FOUND: Msg.DOES_NOT_EXIST,
71160
71322
  GAPI.INVALID_MESSAGE_ID: Msg.INVALID_MESSAGE_ID,
71161
- GAPI.FAILED_PRECONDITION: Msg.FAILED_PRECONDITION}
71323
+ GAPI.FAILED_PRECONDITION: Msg.FAILED_PRECONDITION,
71324
+ GAPI.QUOTA_EXCEEDED: Msg.QUOTA_EXCEEDED}
71162
71325
 
71163
71326
  def _callbackProcessMessage(request_id, _, exception):
71164
71327
  ri = request_id.splitlines()
@@ -71169,7 +71332,9 @@ def _processMessagesThreads(users, entityType):
71169
71332
  csvPF.WriteRow({'User': ri[RI_ENTITY], entityHeader: ri[RI_ITEM], 'action': Act.Performed()})
71170
71333
  else:
71171
71334
  http_status, reason, message = checkGAPIError(exception)
71172
- _processMessageFailed(ri[RI_ENTITY], ri[RI_ITEM], getHTTPError(_GMAIL_ERROR_REASON_TO_MESSAGE_MAP, http_status, reason, message), int(ri[RI_J]), int(ri[RI_JCOUNT]))
71335
+ _processMessageFailed(ri[RI_ENTITY], ri[RI_ITEM],
71336
+ getHTTPError(_GMAIL_ERROR_REASON_TO_MESSAGE_MAP, http_status, reason, message),
71337
+ int(ri[RI_J]), int(ri[RI_JCOUNT]))
71173
71338
 
71174
71339
  def _batchProcessMessagesThreads(service, function, user, jcount, messageIds, **kwargs):
71175
71340
  svcargs = dict([('userId', 'me'), ('id', None), ('fields', '')]+list(kwargs.items())+GM.Globals[GM.EXTRA_ARGS_LIST])
@@ -71267,7 +71432,9 @@ def _processMessagesThreads(users, entityType):
71267
71432
  continue
71268
71433
  if parameters['messageEntity'] is None:
71269
71434
  if parameters['maxToProcess'] and jcount > parameters['maxToProcess']:
71270
- entityNumEntitiesActionNotPerformedWarning([Ent.USER, user], entityType, jcount, Msg.COUNT_N_EXCEEDS_MAX_TO_PROCESS_M.format(jcount, Act.ToPerform(), parameters['maxToProcess']), i, count)
71435
+ entityNumEntitiesActionNotPerformedWarning([Ent.USER, user], entityType, jcount,
71436
+ Msg.COUNT_N_EXCEEDS_MAX_TO_PROCESS_M.format(jcount, Act.ToPerform(), parameters['maxToProcess']),
71437
+ i, count)
71271
71438
  continue
71272
71439
  if not parameters['doIt']:
71273
71440
  entityNumEntitiesActionNotPerformedWarning([Ent.USER, user], entityType, jcount, Msg.USE_DOIT_ARGUMENT_TO_PERFORM_ACTION, i, count)
gam/gamlib/glmsgs.py CHANGED
@@ -465,6 +465,7 @@ PROCESSING_ITEM_N = '{0},0,Processing item {1}\n'
465
465
  PROCESSING_ITEM_N_OF_M = '{0},0,Processing item {1}/{2}\n'
466
466
  PROFILE_PHOTO_NOT_FOUND = 'Profile photo not found'
467
467
  PROFILE_PHOTO_IS_DEFAULT = 'Profile photo is default'
468
+ QUOTA_EXCEEDED = 'Quota exceeded'
468
469
  REASON_ONLY_VALID_WITH_CONTENTRESTRICTIONS_READONLY_TRUE = 'reason only valid with contentrestrictions readonly true'
469
470
  REAUTHENTICATION_IS_NEEDED = 'Reauthentication is needed, please run\n\ngam oauth create'
470
471
  RECOMMEND_RUNNING_GAM_ROTATE_SAKEY = 'Recommend running "gam rotate sakey" to get a new key\n'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gam7
3
- Version: 7.18.4
3
+ Version: 7.18.6
4
4
  Summary: CLI tool to manage Google Workspace
5
5
  Project-URL: Homepage, https://github.com/GAM-team/GAM
6
6
  Project-URL: Issues, https://github.com/GAM-team/GAM/issues
@@ -1,4 +1,4 @@
1
- gam/__init__.py,sha256=lSFipSI6fSlg0J9H08IWN05Mo_kIh61EeR86LIEGQ-c,3577219
1
+ gam/__init__.py,sha256=E5u75yFxYquGMVAfkhxCDcSpYauMaL2akfztrblZEPo,3584006
2
2
  gam/__main__.py,sha256=amz0-959ph6zkZKqjaar4n60yho-T37w6qWI36qx0CA,1049
3
3
  gam/cacerts.pem,sha256=82Ak7btW_2XvocLUvAwPmpx8Chi0oqtZUG1gseLK_t4,50235
4
4
  gam/cbcm-v1.1beta1.json,sha256=xO5XloCQQULmPbFBx5bckdqmbLFQ7sJ2TImhE1ysDIY,19439
@@ -31,7 +31,7 @@ gam/gamlib/glgapi.py,sha256=pdBbwNtnCwFWxJGaP-_3hdTjSNoOCJF2yo76WdQOi1k,40426
31
31
  gam/gamlib/glgdata.py,sha256=weRppttWm6uRyqtBoGPKoHiNZ2h28nhfUV4J_mbCszY,2707
32
32
  gam/gamlib/glglobals.py,sha256=J0xcHggVrUBzHJ5GruenKV-qV1zPKcK2qWgAgN3i5Jw,9608
33
33
  gam/gamlib/glindent.py,sha256=RfBa2LDfLIqPLL5vMfC689TCVmqn8xf-qulSzkiatrc,1228
34
- gam/gamlib/glmsgs.py,sha256=Acd7kdtYcBJwTxQIosXR3cEc4ze8yeMQvFMlFb9e9Qs,33963
34
+ gam/gamlib/glmsgs.py,sha256=vephDvTNbv55f79QzZWEKDcBTXr8knrwDxvx-1TYM6M,33997
35
35
  gam/gamlib/glskus.py,sha256=e1u3zw1MGQjBgAFXqjrGWQl2d7eYpVlMYGpIKNwjskQ,15360
36
36
  gam/gamlib/gluprop.py,sha256=IyPLCyvn7-NHTUenM71YPQPXRZXx6CB5q-GtJ-FYd1c,11461
37
37
  gam/gamlib/glverlibs.py,sha256=xoQXiwcE_-HVYKv-VYA8O0mazRsc9mN-_ysj1dAlMyc,992
@@ -65,8 +65,8 @@ gam/googleapiclient/discovery_cache/base.py,sha256=yCDPtxnbNN-p5_9fzBacC6P3wcUPl
65
65
  gam/googleapiclient/discovery_cache/file_cache.py,sha256=sim3Mg4HgRYo3vX75jvcKy_aV568EvIrtBfvfbw-044,4774
66
66
  gam/iso8601/__init__.py,sha256=Z2PsYbXgAH5a5xzUvgczCboPzqWpm65kRcIngCnhViU,1218
67
67
  gam/iso8601/iso8601.py,sha256=Li2FHZ4sBTWuthuQhyCvmvj0j6At8JbGzkSv2fc2RHU,4384
68
- gam7-7.18.4.dist-info/METADATA,sha256=9Jont_975UdHfv5JG2oX6m9QUjoCE-wMBIpGS_UR6xg,2940
69
- gam7-7.18.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
- gam7-7.18.4.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
- gam7-7.18.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
- gam7-7.18.4.dist-info/RECORD,,
68
+ gam7-7.18.6.dist-info/METADATA,sha256=0RPFGDNkA24f5tyNH_NHgVcrdkiDKXHU6ZP-6F-cmQE,2940
69
+ gam7-7.18.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
70
+ gam7-7.18.6.dist-info/entry_points.txt,sha256=HVUM5J7dA8YwvJfG30jiLefR19ExMs387TWugWd9sf4,42
71
+ gam7-7.18.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
72
+ gam7-7.18.6.dist-info/RECORD,,
File without changes