diff --git a/Testing/RegoTests/classroom/classroom05_test.rego b/Testing/RegoTests/classroom/classroom05_test.rego new file mode 100644 index 00000000..f2f2942b --- /dev/null +++ b/Testing/RegoTests/classroom/classroom05_test.rego @@ -0,0 +1,188 @@ +package classroom +import future.keywords + +# +# GWS.CLASSROOM.5.1v0.2 +#-- + +test_ClassroomCreation_Correct_V1 if { + # Test only teachers can unenroll students when there's only one event + PolicyId := "GWS.CLASSROOM.5.1v0.2" + Output := tests with input as { + "classroom_logs": {"items": [ + { + "id": {"time": "2022-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "3"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + } + ]}, + "tenant_info": { + "topLevelOU": "Test Top-Level OU" + } + } + + RuleOutput := [Result | some Result in Output; Result.PolicyId == PolicyId] + count(RuleOutput) == 1 + RuleOutput[0].RequirementMet + not RuleOutput[0].NoSuchEvent + RuleOutput[0].ReportDetails == "Requirement met in all OUs and groups." +} + +test_ClassroomCreation_Correct_V2 if { + # Test when there's multiple events, with the chronological latest + # correct but not last in json list + PolicyId := "GWS.CLASSROOM.5.1v0.2" + Output := tests with input as { + "classroom_logs": {"items": [ + { + "id": {"time": "2022-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "3"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + }, + { + "id": {"time": "2021-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "2"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + } + ]}, + "tenant_info": { + "topLevelOU": "Test Top-Level OU" + } + } + + RuleOutput := [Result | some Result in Output; Result.PolicyId == PolicyId] + count(RuleOutput) == 1 + RuleOutput[0].RequirementMet + not RuleOutput[0].NoSuchEvent + RuleOutput[0].ReportDetails == "Requirement met in all OUs and groups." +} + +# No tests for multiple OUs, inheritance, groups, etc as this setting can't be controlled at the OU or group level + +test_ClassroomCreation_Incorrect_V1 if { + # Test when there's only one event and it's wrong + PolicyId := "GWS.CLASSROOM.5.1v0.2" + Output := tests with input as { + "classroom_logs": {"items": [ + { + "id": {"time": "2022-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "1"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + } + ]}, + "tenant_info": { + "topLevelOU": "Test Top-Level OU" + } + } + + RuleOutput := [Result | some Result in Output; Result.PolicyId == PolicyId] + count(RuleOutput) == 1 + not RuleOutput[0].RequirementMet + not RuleOutput[0].NoSuchEvent + RuleOutput[0].ReportDetails == concat("", [ + "The following OUs are non-compliant:" + ]) +} + +test_ClassroomCreation_Incorrect_V2 if { + # Test when there's multiple events, with the chronological latest + # incorrect but not last in json list + PolicyId := "GWS.CLASSROOM.5.1v0.2" + Output := tests with input as { + "classroom_logs": {"items": [ + { + "id": {"time": "2022-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "2"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + }, + { + "id": {"time": "2021-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "TeacherPermissionsSettingProto who_can_create_class"}, + {"name": "NEW_VALUE", "value": "3"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + } + ]}, + "tenant_info": { + "topLevelOU": "Test Top-Level OU" + } + } + + RuleOutput := [Result | some Result in Output; Result.PolicyId == PolicyId] + count(RuleOutput) == 1 + not RuleOutput[0].RequirementMet + not RuleOutput[0].NoSuchEvent + RuleOutput[0].ReportDetails == concat("", [ + "The following OUs are non-compliant:" + ]) +} + + +test_ClassroomCreation_Incorrect_V3 if { + # Test when there no applicable event + PolicyId := "GWS.CLASSROOM.5.1v0.2" + Output := tests with input as { + "classroom_logs": {"items": [ + { + "id": {"time": "2022-12-20T00:02:28.672Z"}, + "events": [{ + "parameters": [ + {"name":"SETTING_NAME", + "value": "something else"}, + {"name": "NEW_VALUE", "value": "false"}, + {"name": "ORG_UNIT_NAME", "value": "Test Top-Level OU"}, + ] + }] + } + ]}, + "tenant_info": { + "topLevelOU": "Test Top-Level OU" + } + } + + RuleOutput := [Result | some Result in Output; Result.PolicyId == PolicyId] + count(RuleOutput) == 1 + not RuleOutput[0].RequirementMet + RuleOutput[0].NoSuchEvent + RuleOutput[0].ReportDetails == concat("", [ + "No relevant event in the current logs for the top-level OU, Test Top-Level OU. ", + "While we are unable to determine the state from the logs, the default setting ", + "is non-compliant; manual check recommended." + ]) +} diff --git a/baselines/Google Classroom Minimum Viable Secure Configuration Baseline v0.2.md b/baselines/Google Classroom Minimum Viable Secure Configuration Baseline v0.2.md index 8f480eb4..bdf757e3 100644 --- a/baselines/Google Classroom Minimum Viable Secure Configuration Baseline v0.2.md +++ b/baselines/Google Classroom Minimum Viable Secure Configuration Baseline v0.2.md @@ -16,6 +16,7 @@ This baseline is based on Google documentation available at [Google Workspace Ad - [Classroom API](#2-classroom-api) - [Roster Import](#3-roster-import) - [Student Unenrollment](#4-student-unenrollment) +- [Class Creation](#5-class-creation) Settings can be assigned to certain users within Google Workspace through organizational units, configuration groups, or individually. Before changing a setting, the user can select the organizational unit, configuration group, or individual users to which they want to apply changes. @@ -181,3 +182,42 @@ To configure the settings for Student Unenrollment: 3. Select **Student unenrollment**. 4. Select **Teachers Only**. 5. Select **Save**. + +## 5. Class Creation + +The first time users sign in to Classroom, they self-identify as either a student or teacher. Users who identify as teachers will be marked as a pending teacher until an administrator verifies them. Google Classroom allows administrators to restrict class creation to only verified teachers. + +### Policy + +#### GWS.CLASSROOM.5.1v0.2 +Class creation SHALL be restricted to verified teachers only. + +- _Rationale:_ Allowing pending teachers to create classes potentially allows students to impersonate teachers and exploit the trusted relationship between teacher and student, e.g., to phish sensitive information from the students. Restricting class creation to verified teachers reduces this risk. +- _Last modified:_ June 21, 2024 + +- MITRE ATT&CK TTP Mapping + - [T1656: Impersonation](https://attack.mitre.org/techniques/T1656/) + - [T534: Internal Spearphishing](https://attack.mitre.org/techniques/T1534/) + - [T1598: Phishing for Information](https://attack.mitre.org/techniques/T1598/) + - [T1598:002: Phishing for Information: Spearphishing Attachment](https://attack.mitre.org/techniques/T1598/002/) + - [T1598:003: Phishing for Information: Spearphishing Link](https://attack.mitre.org/techniques/T1598/003/) + - [T1598:004: Phishing for Information: Spearphishing Voice](https://attack.mitre.org/techniques/T1598/004/) + +### Resources + +- [Verify teachers and set permissions](https://support.google.com/edu/classroom/answer/6071551?hl=en) + +### Prerequisites + +- None + +### Implementation +To configure the settings for Class Creation: + +#### GWS.CLASSROOM.5.1v0.2 Instructions +1. Sign in to the [Google Admin Console](https://admin.google.com). +2. Select **Apps** -\> **Additional Google Service** -\> **Classroom**. +3. Select **General Settings**. +4. Select **Teacher permissions**. +5. Select **Verified teachers only** for **Who can create classes?** +5. Select **Save**. diff --git a/drift-rules/GWS Drift Monitoring Rules - Classroom.csv b/drift-rules/GWS Drift Monitoring Rules - Classroom.csv index 1d0c7a4b..3dd9fd43 100644 --- a/drift-rules/GWS Drift Monitoring Rules - Classroom.csv +++ b/drift-rules/GWS Drift Monitoring Rules - Classroom.csv @@ -3,4 +3,5 @@ GWS.CLASSROOM.1.1v0.2,Who can join classes in your domain SHALL be set to Users GWS.CLASSROOM.1.2v0.2,Which classes can users in your domain join SHALL be set to Classes in your domain only,Admin Log Events,Change Application Setting,ClassMembershipSettingProto which_classes_can_users_join,1,rules/00gjdgxs0hj2dit,JK 10-20-23 @ 13:23 GWS.CLASSROOM.2.1v0.2,Classroom API SHALL be disabled for users,Admin Log Events,Change Application Setting,ApiDataAccessSettingProto api_access_enabled,false,rules/00gjdgxs3aafl8p,JK 10-20-23 @ 13:31 GWS.CLASSROOM.3.1v0.2,Roster import with Clever SHOULD be turned off,Admin Log Events,Change Application Setting,RosterImportSettingsProto sis_integrator,SIS_INTEGRATOR_NONE,rules/00gjdgxs25t0l8g,JK 10-20-23 @ 13:42 -GWS.CLASSROOM.4.1v0.2,Who can unenroll students from classes SHALL be set to Teachers Only,Admin Log Events,Change Application Setting,StudentUnenrollmentSettingsProto who_can_unenroll_students,ONLY_TEACHERS_CAN_UNENROLL_STUDENTS,rules/00gjdgxs44rgreu,JK 10-20-23 @ 13:50 \ No newline at end of file +GWS.CLASSROOM.4.1v0.2,Who can unenroll students from classes SHALL be set to Teachers Only,Admin Log Events,Change Application Setting,StudentUnenrollmentSettingsProto who_can_unenroll_students,ONLY_TEACHERS_CAN_UNENROLL_STUDENTS,rules/00gjdgxs44rgreu,JK 10-20-23 @ 13:50 +GWS.CLASSROOM.5.1v0.2,Class creation SHALL be restricted to verified teachers only.,Admin Log Events,Change Application Setting,TeacherPermissionsSettingProto who_can_create_class,rules/00gjdgxs4cfwumr,JK 06-21-24 @ 11:58 \ No newline at end of file diff --git a/rego/Classroom.rego b/rego/Classroom.rego index 2d1d1b4c..d31d4c43 100644 --- a/rego/Classroom.rego +++ b/rego/Classroom.rego @@ -311,3 +311,67 @@ if { Status := count(NonCompliantOUs4_1) == 0 } #-- + + +################### +# GWS.CLASSROOM.5 # +################### + +# +# Baseline GWS.CLASSROOM.5.1v0.2 +#-- +GetFriendlyValue5_1(Value) := "anyone in this domain" if { + Value == "1" +} else := "all pending and verified teachers" if { + Value == "2" +} else := Value + +NonCompliantOUs5_1 contains { + "Name": OU, + "Value": concat(" ", [ + "Who can create classes is set to", + GetFriendlyValue5_1(LastEvent.NewValue) + ]) +} if { + some OU in utils.OUsWithEvents + Events := utils.FilterEventsOU(LogEvents, "TeacherPermissionsSettingProto who_can_create_class", OU) + # Ignore OUs without any events. We're already asserting that the + # top-level OU has at least one event; for all other OUs we assume + # they inherit from a parent OU if they have no events. + count(Events) > 0 + LastEvent := utils.GetLastEvent(Events) + LastEvent.NewValue != "3" + LastEvent.NewValue != "DELETE_APPLICATION_SETTING" +} + +tests contains { + "PolicyId": "GWS.CLASSROOM.5.1v0.2", + "Criticality": "Shall", + "ReportDetails": utils.NoSuchEventDetails(DefaultSafe, utils.TopLevelOU), + "ActualValue": "No relevant event in the current logs", + "RequirementMet": DefaultSafe, + "NoSuchEvent": true +} +if { + DefaultSafe := false + SettingName := "TeacherPermissionsSettingProto who_can_create_class" + Events := utils.FilterEventsOU(LogEvents, SettingName, utils.TopLevelOU) + count(Events) == 0 +} + +tests contains { + "PolicyId": "GWS.CLASSROOM.5.1v0.2", + "Criticality": "Shall", + "ReportDetails": utils.ReportDetails(NonCompliantOUs5_1, []), + "ActualValue": {"NonCompliantOUs": NonCompliantOUs5_1}, + "RequirementMet": Status, + "NoSuchEvent": false +} +if { + SettingName := "TeacherPermissionsSettingProto who_can_create_class" + Events := utils.FilterEventsOU(LogEvents, SettingName, utils.TopLevelOU) + count(Events) > 0 + Status := count(NonCompliantOUs5_1) == 0 +} +#-- +