def move_to_default_ou(self, user_email): """Corrects the current ou to be default during user actions. Args: user_email: str, The email of the acting user. Raises: UnableToMoveToDefaultOUError: when the directory api call fails to move the device into the default OU. """ if self.current_ou != constants.ORG_UNIT_DICT['DEFAULT']: directory_client = directory.DirectoryApiClient( user_email=user_email) try: directory_client.move_chrome_device_org_unit( device_id=self.chrome_device_id, org_unit_path=constants.ORG_UNIT_DICT['DEFAULT']) except directory.DirectoryRPCError as err: raise UnableToMoveToDefaultOUError( _FAILED_TO_MOVE_DEVICE_MSG % (self.identifier, constants.ORG_UNIT_DICT['DEFAULT'], str(err))) else: self.current_ou = constants.ORG_UNIT_DICT['DEFAULT'] self.ou_changed_date = datetime.datetime.utcnow()
def get_device(self, request): """Gets a device using any identifier in device_messages.DeviceRequest.""" device = _get_device(request) if not device.enrolled: raise endpoints.BadRequestException( device_model.DEVICE_NOT_ENROLLED_MSG % device.identifier) user_email = user_lib.get_user_email() datastore_user = user_model.User.get_user(user_email) if (permissions.Permissions.READ_DEVICES not in datastore_user.get_permissions()): if device.assigned_user != user_email: raise endpoints.UnauthorizedException( 'You do not have the proper permission to perform this action. ' 'Please contact your IT administrator if you feel like this is in ' 'error.') directory_client = directory.DirectoryApiClient(user_email) try: given_name = directory_client.given_name(user_email) except (directory.DirectoryRPCError, directory.GivenNameDoesNotExistError): given_name = None message = api_utils.build_device_message_from_model( device, config_model.Config.get('allow_guest_mode')) message.given_name = given_name return message
def sync_user_roles(): """Syncs all of the elevated user roles for each user in Google groups.""" logging.info( 'Using admin account (%s) to sync users.', constants.ADMIN_USERNAME) directory_client = directory.DirectoryApiClient( user_email=constants.ADMIN_USERNAME) technical_admin_users_from_group = _get_users_directory( constants.TECHNICAL_ADMINS_GROUP, directory_client) operational_admin_users_from_group = _get_users_directory( constants.OPERATIONAL_ADMINS_GROUP, directory_client) technician_users_from_group = _get_users_directory( constants.TECHNICIANS_GROUP, directory_client) ndb_technical_admin_users = ( user_model.User.query(user_model.User.roles.IN( [permissions.TECHNICAL_ADMIN_ROLE.name])).fetch(keys_only=True)) ndb_operational_admin_users = ( user_model.User.query(user_model.User.roles.IN( [permissions.OPERATIONAL_ADMIN_ROLE.name])).fetch(keys_only=True)) ndb_technician_users = ( user_model.User.query(user_model.User.roles.IN( [permissions.TECHNICIAN_ROLE.name])).fetch(keys_only=True)) _add_or_remove_user_roles( users_keys=ndb_technical_admin_users, group_users=technical_admin_users_from_group, role=permissions.TECHNICAL_ADMIN_ROLE.name) _add_or_remove_user_roles( users_keys=ndb_operational_admin_users, group_users=operational_admin_users_from_group, role=permissions.OPERATIONAL_ADMIN_ROLE.name) _add_or_remove_user_roles( users_keys=ndb_technician_users, group_users=technician_users_from_group, role=permissions.TECHNICIAN_ROLE.name)
def create_unenrolled(cls, device_id, user_email): """Creates a Device but leave it unenrolled from the Grab n Go program. Args: device_id: str, a Chrome Device ID to pass to the directory API. user_email: str, email address of the user making the request. Returns: The newly created device. Raises: DeviceCreationError: if the Directory API doesn't find this device in the org or the info retrieved from the Directory API is incomplete. """ directory_client = directory.DirectoryApiClient(user_email) directory_info = directory_client.get_chrome_device(device_id) if not directory_info: raise DeviceCreationError(_DEVICE_ID_NOT_FOUND % device_id) try: device = cls( serial_number=directory_info[directory.SERIAL_NUMBER].upper(), enrolled=False, device_model=directory_info.get(directory.MODEL), current_ou=directory_info[directory.ORG_UNIT_PATH], chrome_device_id=directory_info[directory.DEVICE_ID]) except KeyError: raise DeviceCreationError(_DIRECTORY_INFO_INCOMPLETE_MSG) device.put() return device
def get_loan(self, request): """Get the current loan for a given Chrome device.""" if not request.device_id: raise endpoints.BadRequestException(_NO_DEVICE_ID_MSG) device = device_model.Device.get(chrome_device_id=request.device_id) if not device: raise endpoints.NotFoundException(_NOT_GNG_MSG) if request.need_name: user_email = user_lib.get_user_email() directory_client = directory.DirectoryApiClient( user_email=user_email) try: given_name = directory_client.given_name(user_email=user_email) except (directory.DirectoryRPCError, directory.GivenNameDoesNotExistError): given_name = None else: given_name = None guest_enabled, max_extend_date, due_date, guest_permitted = ( device_api.get_loan_data(device)) return chrome_message.LoanResponse(due_date=due_date, max_extend_date=max_extend_date, given_name=given_name, guest_permitted=guest_permitted, guest_enabled=guest_enabled)
def test_get_all_users_in_group(self, returns, expected_result): test_client = directory.DirectoryApiClient(loanertest.USER_EMAIL) with mock.patch.object( test_client, 'users_in_group') as mock_users_in_group: mock_users_in_group.side_effect = returns actual_result = test_client.get_all_users_in_group( 'users@{}'.format(loanertest.USER_DOMAIN)) self.assertEqual(expected_result, actual_result)
def test_get_org_unit_fail(self): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 404), 'NOT USED.') self.mock_client.orgunits.side_effect = raise_error directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual(None, directory_client.get_org_unit(self.org_unit_path))
def test_get_chrome_device_fail(self): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 404), 'NOT USED.') self.mock_client.chromeosdevices.side_effect = raise_error directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual(None, directory_client.get_chrome_device(self.device_id))
def test_get_chrome_device_by_serial_key_error(self, mock_logging): self.mock_client.chromeosdevices.side_effect = KeyError with self.assertRaisesRegexp( directory.DeviceDoesNotExistError, directory._NO_DEVICE_MSG % self.serial_number): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.get_chrome_device_by_serial(self.serial_number) self.assertEqual(mock_logging.error.call_count, 1)
def test_disable_already_diabled_chrome_device_error(self): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 412), 'NOT USED.') self.mock_client.chromeosdevices.side_effect = raise_error with self.assertRaises(directory.DeviceAlreadyDisabledError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.disable_chrome_device(self.device_id)
def test_user_name_key_error(self, mock_logging): def raise_error(): raise KeyError('No given name.') self.mock_client.users.side_effect = raise_error with self.assertRaises(directory.GivenNameDoesNotExistError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.given_name(loanertest.USER_EMAIL) self.assertEqual(mock_logging.info.call_count, 2)
def test_user_name_url_error(self, mock_log_error): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.users.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.given_name(loanertest.USER_EMAIL) mock_log_error.assert_called_once_with('You lose')
def test_users_in_group_url_error(self, mock_log_error): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.members.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.users_in_group(self.group_key) mock_log_error.assert_called_once_with('You lose')
def test_reenable_chrome_device_error(self, mock_log_error): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.chromeosdevices.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.reenable_chrome_device(self.device_id) mock_log_error.assert_called_once_with('You lose')
def test_insert_org_unit_error(self, mock_log_error): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.orgunits.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.insert_org_unit(self.org_unit_name) mock_log_error.assert_called_once_with('You lose')
def get_users_for_group(group_name): """Retrieves users for a given group. Args: group_name: str, the name of the group to get membership for. Returns: A list of all user's email addresses in the group provided. """ directory_client = directory.DirectoryApiClient( user_email=constants.ADMIN_USERNAME) return directory_client.get_all_users_in_group(group_name)
def test_user_name_url_error(self, mock_logging): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.users.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.given_name(loanertest.USER_EMAIL) self.assertEqual(mock_logging.error.call_count, 1)
def test_users_in_group_url_error(self, mock_logging): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.members.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.users_in_group(self.group_key) self.assertEqual(mock_logging.error.call_count, 1)
def test_reenable_chrome_device_error(self, mock_logging): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.chromeosdevices.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.reenable_chrome_device(self.device_id) self.assertEqual(mock_logging.error.call_count, 1)
def test_insert_org_unit_error(self, mock_logging): def raise_error(): raise errors.HttpError(FakeResponse('Does not exist', 400), 'NOT USED.') self.mock_client.orgunits.side_effect = raise_error with self.assertRaises(directory.DirectoryRPCError): directory_client = directory.DirectoryApiClient( user_email=self.user_email) directory_client.insert_org_unit(self.org_unit_name) self.assertEqual(mock_logging.error.call_count, 1)
def unlock(self, user_email): """Re-enables a device via the Directory API. Args: user_email: str, email address of the user making the request. """ logging.info('Contacting Directory to unlock (re-enable) Device %s.', self.identifier) client = directory.DirectoryApiClient(user_email) client.reenable_chrome_device(self.chrome_device_id) self.locked = False self.move_to_default_ou(user_email=user_email) self.stream_to_bq(user_email, 'Re-enabling disabled device.') self.put()
def test_reenable_chrome_device(self, mock_logging): mock_chromeosdevices = mock.Mock() self.mock_client.chromeosdevices = mock_chromeosdevices mock_action = mock.Mock() mock_chromeosdevices.return_value.action = mock_action mock_execute = mock.Mock() mock_action.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) directory_client.reenable_chrome_device(self.device_id) self.assertEqual(mock_execute.call_count, 1) self.assertEqual(2, mock_logging.info.call_count)
def unenroll(self, user_email): """Unenrolls a device, removing it from the Grab n Go program. This moves the device to the root Chrome OU, however it does not change its losr or locked attributes, nor does it unlock it if it's locked (i.e., disabled in the Directory API). Args: user_email: str, email address of the user making the request. Returns: The unenrolled device. Raises: FailedToUnenrollError: raised when moving the device's OU fails. """ if self.assigned_user: self._loan_return(user_email) unenroll_ou = config_model.Config.get('unenroll_ou') directory_client = directory.DirectoryApiClient(user_email) try: directory_client.move_chrome_device_org_unit( device_id=self.chrome_device_id, org_unit_path=unenroll_ou) except directory.DirectoryRPCError as err: raise FailedToUnenrollError( _FAILED_TO_MOVE_DEVICE_MSG % (self.identifier, unenroll_ou, str(err))) self.enrolled = False self.due_date = None self.shelf = None self.assigned_user = None self.assignment_date = None self.current_ou = unenroll_ou self.ou_changed_date = datetime.datetime.utcnow() self.mark_pending_return_date = None self.last_reminder = None self.next_reminder = None event_action = 'device_unenroll' try: self = events.raise_event(event_action, device=self) except events.EventActionsError as err: # For any action that is implemented for device_unenroll that is required # for the rest of the logic an error should be raised. If all actions are # not required, eg sending a notification email only, the error should be # logged. logging.error(_EVENT_ACTION_ERROR_MSG, event_action, err) self.put() self.stream_to_bq(user_email, 'Unenrolling device %s.' % self.identifier) return self
def test_disable_chrome_device(self, mock_log_info): mock_chromeosdevices = mock.Mock() self.mock_client.chromeosdevices = mock_chromeosdevices mock_action = mock.Mock() mock_chromeosdevices.return_value.action = mock_action mock_execute = mock.Mock() mock_action.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) directory_client.disable_chrome_device(self.device_id) mock_execute.assert_called_once() self.assertEqual(2, mock_log_info.call_count)
def test_get_org_unit(self): mock_orgunits = mock.Mock() self.mock_client.orgunits = mock_orgunits mock_get = mock.Mock() mock_orgunits.return_value.get = mock_get mock_execute = mock.Mock() mock_execute.return_value = self.fake_org_unit mock_get.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual( self.fake_org_unit, directory_client.get_org_unit(self.org_unit_path))
def sync_user_roles(): """Syncs all of the elevated user roles for each user in Google groups.""" logging.info('Syncing user roles.') client = directory.DirectoryApiClient(constants.ADMIN_EMAIL) superadmins_from_group = client.get_all_users_in_group( constants.SUPERADMINS_GROUP) _add_or_remove_user_roles(superadmins_from_group, 'superadmin') all_roles = user_model.Role.query().fetch() for role in all_roles: if role.associated_group: users_from_group = client.get_all_users_in_group(role.associated_group) _add_or_remove_user_roles(users_from_group, role.name)
def test_get_chrome_device(self): mock_chromeosdevices = mock.Mock() self.mock_client.chromeosdevices = mock_chromeosdevices mock_get = mock.Mock() mock_chromeosdevices.return_value.get = mock_get mock_execute = mock.Mock() mock_execute.return_value = loanertest.TEST_DIR_DEVICE1 mock_get.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual( loanertest.TEST_DIR_DEVICE1, directory_client.get_chrome_device(self.device_id))
def test_users_in_group(self): mock_members = mock.Mock() self.mock_client.members = mock_members mock_list = mock.Mock() mock_members.return_value.list = mock_list mock_execute = mock.Mock() fake_members = {'members': [], 'nextPageToken': 'pageToken'} mock_execute.return_value = fake_members mock_list.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual( fake_members, directory_client.users_in_group(self.group_key))
def test_move_chrome_device_org_unit(self, mock_logging): mock_chromeosdevices = mock.Mock() self.mock_client.chromeosdevices = mock_chromeosdevices mock_move_devices_to_ou = mock.Mock() mock_chromeosdevices.return_value.moveDevicesToOu = mock_move_devices_to_ou mock_execute = mock.Mock() mock_move_devices_to_ou.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) directory_client.move_chrome_device_org_unit( self.device_id, self.org_unit_path) self.assertEqual(mock_execute.call_count, 1) self.assertEqual(2, mock_logging.info.call_count)
def test_user_name(self): mock_users = mock.Mock() self.mock_client.users = mock_users mock_get = mock.Mock() mock_users.return_value.get = mock_get mock_execute = mock.Mock() fake_given_name = {'name': {'givenName': 'Dare Devil'}} mock_execute.return_value = fake_given_name mock_get.return_value.execute = mock_execute directory_client = directory.DirectoryApiClient(user_email=self.user_email) self.assertEqual( fake_given_name['name']['givenName'], directory_client.given_name(loanertest.USER_EMAIL))