diff --git a/docs/Cloud-Identity-Policies.md b/docs/Cloud-Identity-Policies.md index c09c744b..bac6154b 100644 --- a/docs/Cloud-Identity-Policies.md +++ b/docs/Cloud-Identity-Policies.md @@ -14,12 +14,15 @@ To use these commands you must update your client access authentication. ``` gam oauth create ... -[*] 19) Cloud Identity - Policy +[R] 19) Cloud Identity - Policy ``` ## Definitions ``` ::= policies/ + ::= "(,)*" + ::= + | | ``` ## Policies @@ -305,26 +308,41 @@ workspace_marketplace.apps_allowlist apps ``` ## Display Cloud Identity Policies +Display selected policies. +``` +gam info policies + [nowarnings] + [formatjson] +``` + +By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display. + +By default, Gam displays the information as an indented list of keys and values. +* `formatjson` - Display the fields in JSON format. + +Display all or filtered policies. ``` gam show policies - [(filter )|(name )] [nowarnings] + [filter ] [nowarnings] [formatjson] ``` By default, all policies are displayed. * `filter ` - Display filtered policies, See https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Policies -* `name ` - Display a specfic policy + +By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display. By default, Gam displays the information as an indented list of keys and values. * `formatjson` - Display the fields in JSON format. ``` gam print policies [todrive *] - [(filter )|(name )] [nowarnings] + [filter ] [nowarnings] [formatjson [quotechar ]] ``` By default, all policies are displayed: * `filter ` - Display filtered policies, See https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Policies -* `name ` - Display a specfic policy + +By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display. By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format, * `formatjson` - Display the fields in JSON format. diff --git a/docs/Collections-of-Items.md b/docs/Collections-of-Items.md index 771e91f7..f35562fd 100644 --- a/docs/Collections-of-Items.md +++ b/docs/Collections-of-Items.md @@ -1,4 +1,4 @@ -!# Collections of Items +# Collections of Items - [Python Regular Expressions](Python-Regular-Expressions) Match function - [Definitions](#definitions) - [ListSelector](#listselector) @@ -144,6 +144,8 @@ Data fields identified in a `csvkmd` argument. | | | | ::= | | | | + ::= + | | ::= | | | | ::= diff --git a/docs/GamUpdates.md b/docs/GamUpdates.md index 1ad71913..354d6760 100644 --- a/docs/GamUpdates.md +++ b/docs/GamUpdates.md @@ -10,6 +10,17 @@ Add the `-s` option to the end of the above commands to suppress creating the `g See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation +### 7.00.30 + +Added command to display selected Cloud Identity policies. +``` +gam info policies + [nowarnings] + [formatjson] +``` + +Removed option `name ` from `gam print|show policies`; use `info policies`. + ### 7.00.29 Added option `name ` to `gam print|show policies` that displays diff --git a/docs/How-to-Upgrade-Legacy-GAM-to-GAM7.md b/docs/How-to-Upgrade-Legacy-GAM-to-GAM7.md index 33d4d9ed..c7ddc4b2 100644 --- a/docs/How-to-Upgrade-Legacy-GAM-to-GAM7.md +++ b/docs/How-to-Upgrade-Legacy-GAM-to-GAM7.md @@ -251,7 +251,7 @@ writes the credentials into the file oauth2.txt. admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt admin@server:/Users/admin$ gam version WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found -GAM 7.00.29 - https://github.com/GAM-team/GAM - pyinstaller +GAM 7.00.30 - https://github.com/GAM-team/GAM - pyinstaller GAM Team Python 3.13.0 64-bit final MacOS Sonoma 14.5 x86_64 @@ -923,7 +923,7 @@ writes the credentials into the file oauth2.txt. C:\>del C:\GAMConfig\oauth2.txt C:\>gam version WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found -GAM7 7.00.29 - https://github.com/GAM-team/GAM - pythonsource +GAM7 7.00.30 - https://github.com/GAM-team/GAM - pythonsource GAM Team Python 3.13.0 64-bit final Windows-10-10.0.17134 AMD64 diff --git a/docs/List-Items.md b/docs/List-Items.md index 436145fd..92dbd1bd 100644 --- a/docs/List-Items.md +++ b/docs/List-Items.md @@ -13,6 +13,7 @@ ::= "(,)*" ::= "(,)*" ::= "(,)*" + ::= "(,)*" ::= "(,)*" ::= "(,)*" ::= "(,)*" diff --git a/docs/Version-and-Help.md b/docs/Version-and-Help.md index 100fa1ac..ada2772b 100644 --- a/docs/Version-and-Help.md +++ b/docs/Version-and-Help.md @@ -3,7 +3,7 @@ Print the current version of Gam with details ``` gam version -GAM 7.00.29 - https://github.com/GAM-team/GAM - pyinstaller +GAM 7.00.30 - https://github.com/GAM-team/GAM - pyinstaller GAM Team Python 3.13.0 64-bit final MacOS Sonoma 14.5 x86_64 @@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00 Print the current version of Gam with details and time offset information ``` gam version timeoffset -GAM 7.00.29 - https://github.com/GAM-team/GAM - pyinstaller +GAM 7.00.30 - https://github.com/GAM-team/GAM - pyinstaller GAM Team Python 3.13.0 64-bit final MacOS Sonoma 14.5 x86_64 @@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second Print the current version of Gam with extended details and SSL information ``` gam version extended -GAM 7.00.29 - https://github.com/GAM-team/GAM - pyinstaller +GAM 7.00.30 - https://github.com/GAM-team/GAM - pyinstaller GAM Team Python 3.13.0 64-bit final MacOS Sonoma 14.5 x86_64 @@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64 Path: /Users/Admin/bin/gam7 Version Check: Current: 5.35.08 - Latest: 7.00.29 + Latest: 7.00.30 echo $? 1 ``` @@ -72,7 +72,7 @@ echo $? Print the current version number without details ``` gam version simple -7.00.29 +7.00.30 ``` In Linux/MacOS you can do: ``` @@ -82,7 +82,7 @@ echo $VER Print the current version of Gam and address of this Wiki ``` gam help -GAM 7.00.29 - https://github.com/GAM-team/GAM +GAM 7.00.30 - https://github.com/GAM-team/GAM GAM Team Python 3.13.0 64-bit final MacOS Sonoma 14.5 x86_64 diff --git a/src/GamCommands.txt b/src/GamCommands.txt index 091a6259..2f748eef 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -665,6 +665,7 @@ If an item contains spaces, it should be surrounded by ". ::= "(,)*" ::= "(,)*" ::= "(,)*" + ::= "(,)*" ::= "(,)*" ::= "(,)*" ::= "(,)*" @@ -1001,6 +1002,8 @@ Specify a collection of items by directly specifying them; the item type is dete | | | | ::= | | | | + ::= + | | ::= | | | | ::= @@ -4072,11 +4075,15 @@ gam update deviceuserstate [clientid ] # Cloud Identity Policies +gam info policies + [nowarnings] + [formatjson] + gam print policies [todrive *] - [(filter )|(name )] [nowarnings] + [filter ] [nowarnings] [formatjson [quotechar ]] gam show policies - [(filter )|(name )] [nowarnings] + [filter ] [nowarnings] [formatjson] # Inbound SSO diff --git a/src/GamUpdate.txt b/src/GamUpdate.txt index 83da5daa..e81ec68d 100644 --- a/src/GamUpdate.txt +++ b/src/GamUpdate.txt @@ -1,3 +1,14 @@ +7.00.30 + +Added command to display selected Cloud Identity policies. +``` +gam info policies + [nowarnings] + [formatjson] +``` + +Removed option `name ` from `gam print|show policies`; use `info policies`. + 7.00.29 Added option `name ` to `gam print|show policies` that displays @@ -94,6 +105,8 @@ as files/folders are being identified for processing. Added option `` to `gam create|update caalevel`. +Updated to Python 3.13.0. + 7.00.15 Added options `timestamp []` and `timeformat ` to `gam create|update drivefile` that allow diff --git a/src/gam/__init__.py b/src/gam/__init__.py index 13232cea..48723834 100755 --- a/src/gam/__init__.py +++ b/src/gam/__init__.py @@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki """ __author__ = 'GAM Team ' -__version__ = '7.00.29' +__version__ = '7.00.30' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' #pylint: disable=wrong-import-position @@ -35089,28 +35089,82 @@ def updateFieldsForCIGroupMatchPatterns(matchPatterns, fieldsList, csvPF=None): CIPOLICY_TIME_OBJECTS = {'createTime', 'updateTime'} +# Policies where GAM should offer additional guidance and information +CIPOLICY_ADDITIONAL_WARNINGS = { + 'settings/drive_and_docs.external_sharing': { + 'warningType': 'SUPERSEDED_POLICY', + 'warningMessage': 'CAUTION: Drive Sharing settings are superseded by Drive Trust Rules if Trust Rules has been enabled for your domain. Drive Trust Rule settings are not available in the Policy API today so GAM is not able to check if Trust Rules is enabled and if the settings/drive_and_docs.external_sharing policies are actually in effect for your domain. If Drive Trust Rules is enabled for your domain then this settings/drive_and_docs.external_sharing policy does not accurately reflect your current Drive sharing settings.' + } +} + +def _cleanPolicy(policy, add_warnings, cd, groups_ci): + # convert any wordlists into spaced strings to reduce output complexity + if policy['setting']['type'] == 'settings/detector.word_list': + policy['setting']['value']['wordList'] = ' '.join(policy['setting']['value']['wordList']['words']) + # add any warnings to applicable policies + if add_warnings and policy['setting']['type'] in CIPOLICY_ADDITIONAL_WARNINGS: + policy['warning'] = CIPOLICY_ADDITIONAL_WARNINGS[policy['setting']['type']] + if groupId := policy['policyQuery'].get('group'): + _, _, policy['policyQuery']['groupEmail'] = convertGroupCloudIDToEmail(groups_ci, groupId) + # all groups are in the root OU so the orgUnit attribute is useless + policy['policyQuery'].pop('orgUnit', None) + elif orgId := policy['policyQuery'].get('orgUnit'): + policy['policyQuery']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgId) + +def _showPolicy(policy, FJQC, i=0, count=0): + if FJQC is not None and FJQC.formatJSON: + printLine(json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS), + ensure_ascii=False, + sort_keys=True)) + return + printEntity([Ent.POLICY, policy['name']], i, count) + Ind.Increment() + policy.pop('name') + showJSON(None, policy, timeObjects=CIPOLICY_TIME_OBJECTS) + printBlankLine() + Ind.Decrement() + +# gam info policies +# [nowarnings] [formatjson] +def doInfoCIPolicies(): + groups_ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS) + ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY) + cd = buildGAPIObject(API.DIRECTORY) + entityList = getEntityList(Cmd.OB_CIPOLICY_NAME_ENTITY) + FJQC = FormatJSONQuoteChar() + add_warnings = True + while Cmd.ArgumentsRemaining(): + myarg = getArgument() + if myarg == 'nowarnings': + add_warnings = False + else: + FJQC.GetFormatJSON(myarg) + i = 0 + count = len(entityList) + for pname in entityList: + i += 1 + if not pname.startswith('policies/'): + pname = 'policies/'+pname + try: + policy = callGAPI(ci.policies(), 'get', + bailOnInternalError=True, + throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR], + name=pname, + fields='name,policyQuery(group,orgUnit,sortOrder),type,setting') + _cleanPolicy(policy, add_warnings, cd, groups_ci) + _showPolicy(policy, FJQC, i, count) + except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e: + entityActionFailedWarning([Ent.POLICY, pname], str(e), i, count) + continue + # gam print policies [todrive *] -# [(filter )|(name )] [nowarnings] +# [filter ] [nowarnings] # [formatjson [quotechar ]] # gam show policies -# [(filter )|(name )] [nowarnings] +# [filter ] [nowarnings] # [formatjson] def doPrintShowCIPolicies(): - def _showPolicy(policy, FJQC, i=0, count=0): - if FJQC is not None and FJQC.formatJSON: - printLine(json.dumps(cleanJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS), - ensure_ascii=False, - sort_keys=True)) - return - printEntity([Ent.POLICY, policy['name']], i, count) - Ind.Increment() - policy.pop('name') - showJSON(None, policy, timeObjects=CIPOLICY_TIME_OBJECTS) - if not pname: - printBlankLine() - Ind.Decrement() - def _printPolicy(policy): row = flattenJSON(policy, timeObjects=CIPOLICY_TIME_OBJECTS) if not FJQC.formatJSON: @@ -35121,19 +35175,12 @@ def doPrintShowCIPolicies(): ensure_ascii=False, sort_keys=True)}) - # Policies where GAM should offer additional guidance and information - warnings = { - 'settings/drive_and_docs.external_sharing': { - 'warningType': 'SUPERSEDED_POLICY', - 'warningMessage': 'CAUTION: Drive Sharing settings are superseded by Drive Trust Rules if Trust Rules has been enabled for your domain. Drive Trust Rule settings are not available in the Policy API today so GAM is not able to check if Trust Rules is enabled and if the settings/drive_and_docs.external_sharing policies are actually in effect for your domain. If Drive Trust Rules is enabled for your domain then this settings/drive_and_docs.external_sharing policy does not accurately reflect your current Drive sharing settings.' - } - } groups_ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS) ci = buildGAPIObject(API.CLOUDIDENTITY_POLICY) cd = buildGAPIObject(API.DIRECTORY) csvPF = CSVPrintFile(['name']) if Act.csvFormat() else None FJQC = FormatJSONQuoteChar(csvPF) - ifilter = pname = None + ifilter = None add_warnings = True while Cmd.ArgumentsRemaining(): myarg = getArgument() @@ -35141,63 +35188,36 @@ def doPrintShowCIPolicies(): csvPF.GetTodriveParameters() elif myarg == 'filter': ifilter = getString(Cmd.OB_STRING) - elif myarg == 'name': - pname = getString(Cmd.OB_STRING) elif myarg == 'nowarnings': add_warnings = False else: FJQC.GetFormatJSONQuoteChar(myarg, True) - if ifilter and pname: - usageErrorExit(Msg.ARE_MUTUALLY_EXCLUSIVE.format('filter', 'name')) - throwReasons = [GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED, GAPI.INTERNAL_ERROR] - fields = 'name,policyQuery(group,orgUnit,sortOrder),type,setting' - if not pname: - printGettingAllAccountEntities(Ent.POLICY, ifilter) - pageMessage = getPageMessage() - try: - policies = callGAPIpages(ci.policies(), 'list', 'policies', - throwReasons=throwReasons, - pageMessage=pageMessage, - filter=ifilter, - fields=f'nextPageToken,policies({fields})', - pageSize=100) - except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e: - entityActionFailedExit([Ent.POLICY, None], str(e)) - else: - try: - policies = [callGAPI(ci.policies(), 'get', - bailOnInternalError=True, - throwReasons=throwReasons, - name=pname, - fields=fields)] - except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied, GAPI.internalError) as e: - entityActionFailedExit([Ent.POLICY, pname], str(e)) + printGettingAllAccountEntities(Ent.POLICY, ifilter) + pageMessage = getPageMessage() + try: + policies = callGAPIpages(ci.policies(), 'list', 'policies', + pageMessage=pageMessage, + throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED], + filter=ifilter, + fields='nextPageToken,policies(name,policyQuery(group,orgUnit,sortOrder),type,setting)', + pageSize=100) + except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e: + entityActionFailedExit([Ent.POLICY, None], str(e)) # Google returns unordered results, sort them by setting type policies = sorted(policies, key=lambda p: p.get('setting', {}).get('type', '')) - for policy in policies: - # convert any wordlists into spaced strings to reduce output complexity - if policy['setting']['type'] == 'settings/detector.word_list': - policy['setting']['value']['wordList'] = ' '.join(policy['setting']['value']['wordList']['words']) - # add any warnings to applicable policies - if add_warnings and policy['setting']['type'] in warnings: - policy['warning'] = warnings[policy['setting']['type']] - if groupId := policy['policyQuery'].get('group'): - _, _, policy['policyQuery']['groupEmail'] = convertGroupCloudIDToEmail(groups_ci, groupId) - # all groups are in the root OU so the orgUnit attribute is useless - policy['policyQuery'].pop('orgUnit', None) - elif orgId := policy['policyQuery'].get('orgUnit'): - policy['policyQuery']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgId) if not csvPF: - jcount = len(policies) - performActionNumItems(jcount, Ent.POLICY) + count = len(policies) + performActionNumItems(count, Ent.POLICY) Ind.Increment() - j = 0 + i = 0 for policy in policies: - j += 1 - _showPolicy(policy, FJQC, j, jcount) + i += 1 + _cleanPolicy(policy, add_warnings, cd, groups_ci) + _showPolicy(policy, FJQC, i, count) Ind.Decrement() else: for policy in policies: + _cleanPolicy(policy, add_warnings, cd, groups_ci) _printPolicy(policy) if csvPF: csvPF.writeCSVfile('Policies') @@ -75125,6 +75145,7 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_CHROMESCHEMA: doInfoChromePolicySchemas, Cmd.ARG_CIGROUP: doInfoCIGroups, Cmd.ARG_CIGROUPMEMBERS: doInfoCIGroupMembers, + Cmd.ARG_CIPOLICY: doInfoCIPolicies, Cmd.ARG_CONTACT: doInfoDomainContacts, Cmd.ARG_COURSE: doInfoCourse, Cmd.ARG_COURSES: doInfoCourses, @@ -75212,7 +75233,7 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CIGROUP: doPrintCIGroups, Cmd.ARG_CIGROUPMEMBERS: doPrintCIGroupMembers, - Cmd.ARG_CIPOLICIES: doPrintShowCIPolicies, + Cmd.ARG_CIPOLICY: doPrintShowCIPolicies, Cmd.ARG_CLASSROOMINVITATION: doPrintShowClassroomInvitations, Cmd.ARG_CONTACT: doPrintShowDomainContacts, Cmd.ARG_COURSE: doPrintCourses, @@ -75341,7 +75362,7 @@ MAIN_COMMANDS_WITH_OBJECTS = { Cmd.ARG_CHROMESCHEMA: doPrintShowChromeSchemas, Cmd.ARG_CHROMEVERSIONS: doPrintShowChromeVersions, Cmd.ARG_CIGROUPMEMBERS: doShowCIGroupMembers, - Cmd.ARG_CIPOLICIES: doPrintShowCIPolicies, + Cmd.ARG_CIPOLICY: doPrintShowCIPolicies, Cmd.ARG_CLASSROOMINVITATION: doPrintShowClassroomInvitations, Cmd.ARG_CONTACT: doPrintShowDomainContacts, Cmd.ARG_CROSTELEMETRY: doInfoPrintShowCrOSTelemetry, @@ -75525,6 +75546,7 @@ MAIN_COMMANDS_OBJ_ALIASES = { Cmd.ARG_CIGROUPSMEMBERS: Cmd.ARG_CIGROUPMEMBERS, Cmd.ARG_CIMEMBER: Cmd.ARG_CIGROUPMEMBERS, Cmd.ARG_CIMEMBERS: Cmd.ARG_CIGROUPMEMBERS, + Cmd.ARG_CIPOLICIES: Cmd.ARG_CIPOLICY, Cmd.ARG_CLASS: Cmd.ARG_COURSE, Cmd.ARG_CLASSES: Cmd.ARG_COURSES, Cmd.ARG_CLASSPARTICIPANTS: Cmd.ARG_COURSEPARTICIPANTS, diff --git a/src/gam/gamlib/glclargs.py b/src/gam/gamlib/glclargs.py index 1629a1fb..1f926767 100644 --- a/src/gam/gamlib/glclargs.py +++ b/src/gam/gamlib/glclargs.py @@ -493,6 +493,7 @@ class GamCLArgs(): ARG_CIGROUPSMEMBERS = 'cigroupsmembers' ARG_CIMEMBER = 'cimember' ARG_CIMEMBERS = 'cimembers' + ARG_CIPOLICY = 'policy' ARG_CIPOLICIES = 'policies' ARG_CLASS = 'class' ARG_CLASSES = 'classes' @@ -844,6 +845,7 @@ class GamCLArgs(): OB_CHROME_VERSION = 'ChromeVersion' OB_CIDR_NETMASK = 'CIDRnetmask' OB_CIGROUP_ALIAS_LIST = "CIGroupAliasList" + OB_CIPOLICY_NAME_ENTITY = 'CIPolicyNameEntity' OB_CLASSROOM_INVITATION_ID_ENTITY = 'ClassroomInvitationIDEntity' OB_CLIENT_ID = 'ClientID' OB_COLLABORATOR_ITEM = 'CollaboratorItem'