Esempio n. 1
0
 /**
  * Construct a user API client, accounting for unified api presence, and fall back to system api user if desired.
  *
  * @param int $muserid The userid to get the outlook token for. If you want to force a system API user client, use an empty
  *                     value here and set $systemfallback to true.
  * @return \local_o365\rest\o365api|bool A constructed user API client (unified or legacy), or false if error.
  */
 public function construct_user_api($muserid = null, $systemfallback = true)
 {
     $unifiedconfigured = \local_o365\rest\unified::is_configured();
     if ($unifiedconfigured === true) {
         $resource = \local_o365\rest\unified::get_resource();
     } else {
         $resource = \local_o365\rest\azuread::get_resource();
     }
     $token = null;
     if (!empty($muserid)) {
         $token = \local_o365\oauth2\token::instance($muserid, $resource, $this->clientdata, $this->httpclient);
     }
     if (empty($token) && $systemfallback === true) {
         $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $this->clientdata, $this->httpclient);
     }
     if (empty($token)) {
         throw new \Exception('No token available for user #' . $muserid);
     }
     if ($unifiedconfigured === true) {
         $apiclient = new \local_o365\rest\unified($token, $this->httpclient);
     } else {
         $apiclient = new \local_o365\rest\azuread($token, $this->httpclient);
     }
     return $apiclient;
 }
 /**
  * Sync sharepoint access for a list of courses and users.
  *
  * @param array $courses The courses to sync.
  * @param array $users The users to sync.
  * @param string $requiredcap The required capability.
  * @param \local\o365\rest\sharepoint $sharepoint Constructed sharepoint API client.
  * @return bool Success/Failure.
  */
 protected function sync_spsiteaccess_for_courses_and_users(array $courses, array $users, $requiredcap, \local_o365\rest\sharepoint $sharepoint)
 {
     global $DB;
     foreach ($courses as $course) {
         $courseid = is_numeric($course) ? $course : $course->id;
         $context = \context_course::instance($courseid);
         $spgroupsql = 'SELECT *
                          FROM {local_o365_coursespsite} site
                          JOIN {local_o365_spgroupdata} grp ON grp.coursespsiteid = site.id
                         WHERE site.courseid = ? AND grp.permtype = ?';
         $spgrouprec = $DB->get_record_sql($spgroupsql, [$courseid, 'contribute']);
         foreach ($users as $user) {
             $userid = is_numeric($user) ? $user : $user->id;
             $userupn = \local_o365\rest\azuread::get_muser_upn($user);
             $hascap = has_capability($requiredcap, $context, $user);
             if ($hascap === true) {
                 // Add to group.
                 $sharepoint->add_user_to_group($userupn, $spgrouprec->groupid, $userid);
             } else {
                 // Remove from group.
                 $sharepoint->remove_user_from_group($userupn, $spgrouprec->groupid, $userid);
             }
         }
     }
     return true;
 }
Esempio n. 3
0
 /**
  * Get an Azure AD API instance.
  *
  * @param string $caller The calling function, used for logging.
  * @return \local_o365\rest\azuread An Azure AD API instance.
  */
 public static function get_azuread_api($caller = 'get_azuread_api')
 {
     $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
     $httpclient = new \local_o365\httpclient();
     $resource = \local_o365\rest\azuread::get_resource();
     $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $clientdata, $httpclient);
     if (!empty($token)) {
         return new \local_o365\rest\azuread($token, $httpclient);
     } else {
         $msg = 'Couldn\'t construct azuread api client because we didn\'t have a system API user token.';
         $caller = '\\local_o365\\feature\\usergroups\\observers::' . $caller;
         \local_o365\utils::debug($msg, $caller);
         return false;
     }
 }
 /**
  * Sync sharepoint access for a list of courses and users.
  *
  * @param array $courses The courses to sync.
  * @param array $users The users to sync.
  * @param string $requiredcap The required capability.
  * @param \local\o365\rest\sharepoint $sharepoint Constructed sharepoint API client.
  * @return bool Success/Failure.
  */
 protected function sync_spsiteaccess_for_courses_and_users(array $courses, array $users, $requiredcap, \local_o365\rest\sharepoint $sharepoint)
 {
     global $DB;
     foreach ($courses as $course) {
         $courseid = is_numeric($course) ? $course : $course->id;
         $context = \context_course::instance($courseid);
         $spgroupsql = 'SELECT *
                          FROM {local_o365_coursespsite} site
                          JOIN {local_o365_spgroupdata} grp ON grp.coursespsiteid = site.id
                         WHERE site.courseid = ? AND grp.permtype = ?';
         $spgrouprec = $DB->get_record_sql($spgroupsql, [$courseid, 'contribute']);
         if (!empty($spgrouprec)) {
             foreach ($users as $user) {
                 $userid = is_numeric($user) ? $user : $user->id;
                 if (!\local_o365\utils::is_o365_connected($userid)) {
                     continue;
                 }
                 $userupn = \local_o365\rest\azuread::get_muser_upn($user);
                 $hascap = has_capability($requiredcap, $context, $user);
                 if ($hascap === true) {
                     // Add to group.
                     try {
                         mtrace('Adding user #' . $userid . ' to group id ' . $spgrouprec->groupid . '...');
                         $sharepoint->add_user_to_group($userupn, $spgrouprec->groupid, $userid);
                     } catch (\Exception $e) {
                         mtrace('Error: ' . $e->getMessage());
                     }
                 } else {
                     // Remove from group.
                     try {
                         mtrace('Removing user #' . $userid . ' from group id ' . $spgrouprec->groupid . '...');
                         $sharepoint->remove_user_from_group($userupn, $spgrouprec->groupid, $userid);
                     } catch (\Exception $e) {
                         mtrace('Error: ' . $e->getMessage());
                     }
                 }
             }
         }
     }
     return true;
 }
 /**
  * Construct an API client.
  *
  * @return \local_o365\rest\o365api|bool A constructed user API client (unified or legacy), or false if error.
  */
 public function get_api()
 {
     $unifiedconfigured = \local_o365\rest\unified::is_configured();
     if ($unifiedconfigured === true) {
         $resource = \local_o365\rest\unified::get_resource();
     } else {
         $resource = \local_o365\rest\azuread::get_resource();
     }
     $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
     $httpclient = new \local_o365\httpclient();
     $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $clientdata, $httpclient);
     if (empty($token)) {
         throw new \Exception('No token available for system user. Please run local_o365 health check.');
     }
     if ($unifiedconfigured === true) {
         $apiclient = new \local_o365\rest\unified($token, $httpclient);
     } else {
         $apiclient = new \local_o365\rest\azuread($token, $httpclient);
     }
     return $apiclient;
 }
Esempio n. 6
0
 /**
  * Sync Sharepoint course site access when a role was assigned or unassigned for a user.
  *
  * @param int $roleid The ID of the role that was assigned/unassigned.
  * @param int $userid The ID of the user that it was assigned to or unassigned from.
  * @param int $contextid The ID of the context the role was assigned/unassigned in.
  * @return bool Success/Failure.
  */
 public static function sync_spsite_access_for_roleassign_change($roleid, $userid, $contextid)
 {
     global $DB;
     $requiredcap = \local_o365\rest\sharepoint::get_course_site_required_capability();
     // Check if the role affected the required capability.
     $rolecapsql = "SELECT *\n                         FROM {role_capabilities}\n                        WHERE roleid = ? AND capability = ?";
     $capassignrec = $DB->get_record_sql($rolecapsql, [$roleid, $requiredcap]);
     if (empty($capassignrec) || $capassignrec->permission == CAP_INHERIT) {
         // Role doesn't affect required capability. Doesn't concern us.
         return false;
     }
     $context = \context::instance_by_id($contextid, IGNORE_MISSING);
     if (empty($context)) {
         // Invalid context, stop here.
         return false;
     }
     if ($context->contextlevel == CONTEXT_COURSE) {
         $courseid = $context->instanceid;
         $user = $DB->get_record('user', ['id' => $userid]);
         if (empty($user)) {
             // Bad userid.
             return false;
         }
         $userupn = \local_o365\rest\azuread::get_muser_upn($user);
         if (empty($userupn)) {
             // No user UPN, can't continue.
             return false;
         }
         $spgroupsql = 'SELECT *
                          FROM {local_o365_coursespsite} site
                          JOIN {local_o365_spgroupdata} grp ON grp.coursespsiteid = site.id
                         WHERE site.courseid = ? AND grp.permtype = ?';
         $spgrouprec = $DB->get_record_sql($spgroupsql, [$courseid, 'contribute']);
         if (empty($spgrouprec)) {
             // No sharepoint group, can't fix that here.
             return false;
         }
         // If the context is a course context we can change SP access now.
         $sharepoint = static::construct_sharepoint_api_with_system_user();
         if (empty($sharepoint)) {
             // O365 not configured.
             return false;
         }
         $hascap = has_capability($requiredcap, $context, $user);
         if ($hascap === true) {
             // Add to group.
             $sharepoint->add_user_to_group($userupn, $spgrouprec->groupid, $user->id);
         } else {
             // Remove from group.
             $sharepoint->remove_user_from_group($userupn, $spgrouprec->groupid, $user->id);
         }
         return true;
     } else {
         if ($context->get_course_context(false) == false) {
             // If the context is higher than a course, we have to run a sync in cron.
             $spaccesssync = new \local_o365\task\sharepointaccesssync();
             $spaccesssync->set_custom_data(['roleid' => $roleid, 'userid' => $userid, 'contextid' => $contextid]);
             \core\task\manager::queue_adhoc_task($spaccesssync);
             return true;
         }
     }
 }
Esempio n. 7
0
 /**
  * Attempt to fix application permissions.
  */
 public function mode_fixappperms()
 {
     $data = new \stdClass();
     $success = false;
     $resource = \local_o365\rest\azuread::get_resource();
     $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
     $httpclient = new \local_o365\httpclient();
     $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $clientdata, $httpclient);
     if (empty($token)) {
         throw new \moodle_exception('errorchecksystemapiuser', 'local_o365');
     }
     $apiclient = new \local_o365\rest\azuread($token, $httpclient);
     $success = $apiclient->push_permissions();
     $data->success = $success;
     if ($success === true) {
         set_config('detectperms', 1, 'local_o365');
     }
     echo $this->ajax_response($data, $success);
 }
Esempio n. 8
0
 /**
  * Transform the full request URL.
  *
  * @param string $requesturi The full request URI, includes the API uri and called endpoint.
  * @return string The transformed full request URI.
  */
 public function transform_full_request_uri($requesturi)
 {
     return parent::transform_full_request_uri($requesturi);
 }
Esempio n. 9
0
 /**
  * Test sync_users method.
  */
 public function test_sync_users()
 {
     global $CFG, $DB;
     for ($i = 1; $i <= 2; $i++) {
         $muser = ['auth' => 'oidc', 'deleted' => '0', 'mnethostid' => $CFG->mnet_localhost_id, 'username' => '00000000-0000-0000-0000-00000000000' . $i, 'firstname' => 'Test', 'lastname' => 'User' . $i, 'email' => 'testuser' . $i . '@example.onmicrosoft.com', 'lang' => 'en'];
         $DB->insert_record('user', (object) $muser);
         $token = ['oidcuniqid' => '00000000-0000-0000-0000-00000000000' . $i, 'authcode' => '000', 'username' => 'testuser' . $i . '@example.onmicrosoft.com', 'scope' => 'test', 'resource' => \local_o365\rest\azuread::get_resource(), 'token' => '000', 'expiry' => '9999999999', 'refreshtoken' => 'fsdfsdf' . $i, 'idtoken' => 'sdfsdfsdf' . $i];
         $DB->insert_record('auth_oidc_token', (object) $token);
     }
     $response = ['value' => [$this->get_aad_userinfo(1), $this->get_aad_userinfo(3)]];
     $response = json_encode($response);
     $httpclient = new \local_o365\tests\mockhttpclient();
     $httpclient->set_response($response);
     $apiclient = new \local_o365\rest\azuread($this->get_mock_token(), $httpclient);
     $aadusers = $apiclient->get_users();
     $apiclient->sync_users($aadusers['value']);
     $existinguser = ['auth' => 'oidc', 'username' => '*****@*****.**'];
     $this->assertTrue($DB->record_exists('user', $existinguser));
     $createduser = ['auth' => 'oidc', 'username' => '*****@*****.**'];
     $this->assertTrue($DB->record_exists('user', $createduser));
     $createduser = $DB->get_record('user', $createduser);
     $this->assertEquals('Test', $createduser->firstname);
     $this->assertEquals('User3', $createduser->lastname);
     $this->assertEquals('*****@*****.**', $createduser->email);
     $this->assertEquals('Toronto', $createduser->city);
     $this->assertEquals('CA', $createduser->country);
     $this->assertEquals('Dev', $createduser->department);
     $this->assertEquals('en', $createduser->lang);
 }
Esempio n. 10
0
 /**
  * Do the job.
  */
 public function execute()
 {
     global $DB;
     $configsetting = get_config('local_o365', 'creategroups');
     if (empty($configsetting)) {
         mtrace('Groups not enabled, skipping...');
         return true;
     }
     $now = time();
     $httpclient = new \local_o365\httpclient();
     $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
     $unifiedresource = \local_o365\rest\unified::get_resource();
     $unifiedtoken = \local_o365\oauth2\systemtoken::instance(null, $unifiedresource, $clientdata, $httpclient);
     if (empty($unifiedtoken)) {
         mtrace('Could not get unified API token.');
         return true;
     }
     $unifiedclient = new \local_o365\rest\unified($unifiedtoken, $httpclient);
     $aadresource = \local_o365\rest\azuread::get_resource();
     $aadtoken = \local_o365\oauth2\systemtoken::instance(null, $aadresource, $clientdata, $httpclient);
     if (empty($aadtoken)) {
         mtrace('Could not get Azure AD token.');
         return true;
     }
     $aadclient = new \local_o365\rest\azuread($aadtoken, $httpclient);
     $siterec = $DB->get_record('course', ['id' => SITEID]);
     $siteshortname = strtolower(preg_replace('/[^a-z0-9]+/iu', '', $siterec->shortname));
     $sql = 'SELECT crs.*
               FROM {course} crs
          LEFT JOIN {local_o365_objects} obj ON obj.type = ? AND obj.subtype = ? AND obj.moodleid = crs.id
              WHERE obj.id IS NULL AND crs.id != ?
              LIMIT 0, 5';
     $params = ['group', 'course', SITEID];
     $courses = $DB->get_recordset_sql($sql, $params);
     foreach ($courses as $course) {
         // Create group.
         $groupname = $siterec->shortname . ': ' . $course->fullname;
         $groupshortname = $siteshortname . '_' . $course->shortname;
         $response = $unifiedclient->create_group($groupname, $groupshortname);
         if (empty($response) || !is_array($response) || empty($response['objectId'])) {
             mtrace('Could not create group for course #' . $course->id);
             var_dump($response);
             continue;
         }
         mtrace('Created group ' . $response['objectId'] . ' for course #' . $course->id);
         $objectrec = ['type' => 'group', 'subtype' => 'course', 'objectid' => $response['objectId'], 'moodleid' => $course->id, 'o365name' => $groupname, 'timecreated' => $now, 'timemodified' => $now];
         $objectrec['id'] = $DB->insert_record('local_o365_objects', (object) $objectrec);
         mtrace('Recorded group object (' . $objectrec['objectid'] . ') into object table with record id ' . $objectrec['id']);
         // It takes a little while for the group object to register.
         mtrace('Waiting 10 seconds for group to register...');
         sleep(10);
         // Add enrolled users to group.
         mtrace('Adding users to group (' . $objectrec['objectid'] . ')');
         $coursecontext = \context_course::instance($course->id);
         list($esql, $params) = get_enrolled_sql($coursecontext);
         $sql = "SELECT u.*,\n                           tok.oidcuniqid as userobjectid\n                      FROM {user} u\n                      JOIN ({$esql}) je ON je.id = u.id\n                      JOIN {auth_oidc_token} tok ON tok.username = u.username AND tok.resource = :tokresource\n                     WHERE u.deleted = 0";
         $params['tokresource'] = 'https://graph.windows.net';
         $enrolled = $DB->get_recordset_sql($sql, $params);
         foreach ($enrolled as $user) {
             $response = $aadclient->add_member_to_group($objectrec['objectid'], $user->userobjectid);
             if ($response === true) {
                 mtrace('Added user #' . $user->id . ' (' . $user->userobjectid . ')');
             } else {
                 mtrace('Could not add user #' . $user->id . ' (' . $user->userobjectid . ')');
                 mtrace('Received: ' . $response);
             }
         }
         $enrolled->close();
     }
     $courses->close();
 }
Esempio n. 11
0
 /**
  * Add users with a given capability in a given context to a Sharepoint group.
  *
  * @param \context $context The context to check for the capability.
  * @param string $capability The capability to check for.
  * @param int $spgroupid The sharepoint group ID to add users to.
  */
 public function add_users_with_capability_to_group($context, $capability, $spgroupid)
 {
     $now = time();
     $users = get_users_by_capability($context, $capability);
     $results = [];
     // Assign users to group.
     foreach ($users as $user) {
         // Only Azure AD users can be added to sharepoint.
         if (\local_o365\utils::is_o365_connected($user->id) !== true) {
             continue;
         }
         try {
             $userupn = \local_o365\rest\azuread::get_muser_upn($user);
         } catch (\Exception $e) {
             continue;
         }
         if (!empty($userupn)) {
             $results[$user->id] = $this->add_user_to_group($userupn, $spgroupid, $user->id);
         }
     }
     return $results;
 }