@@ -635,7 +635,7 @@ public static function get_sync_options() {
635
635
*/
636
636
public static function sync_option_enabled ($ option ) {
637
637
$ options = static ::get_sync_options ();
638
- return (! empty ( $ options [$ option ])) ? true : false ;
638
+ return isset ( $ options [$ option ]);
639
639
}
640
640
641
641
/**
@@ -669,8 +669,17 @@ public function sync_users(array $aadusers = array()) {
669
669
}
670
670
}
671
671
672
+ if ($ aadsync ['emailsync ' ]) {
673
+ $ select = 'SELECT u.email,
674
+ u.username, ' ;
675
+ $ where = ' WHERE u.email ' ;
676
+ } else {
677
+ $ select = 'SELECT u.username, ' ;
678
+ $ where = ' WHERE u.username ' ;
679
+ }
680
+
672
681
list ($ usernamesql , $ usernameparams ) = $ DB ->get_in_or_equal ($ usernames );
673
- $ sql = ' SELECT u.username,
682
+ $ sql = " $ select
674
683
u.id as muserid,
675
684
u.auth,
676
685
tok.id as tokid,
@@ -684,8 +693,8 @@ public function sync_users(array $aadusers = array()) {
684
693
LEFT JOIN {local_o365_connections} conn ON conn.muserid = u.id
685
694
LEFT JOIN {local_o365_appassign} assign ON assign.muserid = u.id
686
695
LEFT JOIN {local_o365_objects} obj ON obj.type = ? AND obj.moodleid = u.id
687
- WHERE u.username ' . $ usernamesql. ' AND u.mnethostid = ? AND u.deleted = ?
688
- ORDER BY CONCAT(u.username, \' ~ \' ) ' ;
// Sort [email protected] before john.smith.
696
+ $ where $ usernamesql AND u.mnethostid = ? AND u.deleted = ?
697
+ ORDER BY CONCAT(u.username, '~') " ;
// Sort [email protected] before john.smith.
689
698
$ params = array_merge (['user ' ], $ usernameparams , [$ CFG ->mnet_localhost_id , '0 ' ]);
690
699
$ existingusers = $ DB ->get_records_sql ($ sql , $ params );
691
700
@@ -715,6 +724,12 @@ public function sync_users(array $aadusers = array()) {
715
724
716
725
foreach ($ aadusers as $ user ) {
717
726
$ this ->mtrace (' ' );
727
+
728
+ if (empty ($ user ['upnlower ' ])) {
729
+ $ this ->mtrace ('Azure AD user missing UPN ( ' . $ user ['objectId ' ] . '); skipping... ' );
730
+ continue ;
731
+ }
732
+
718
733
$ this ->mtrace ('Syncing user ' .$ user ['upnlower ' ]);
719
734
720
735
if (\local_o365 \rest \unified::is_configured ()) {
@@ -723,38 +738,6 @@ public function sync_users(array $aadusers = array()) {
723
738
$ userobjectid = $ user ['objectId ' ];
724
739
}
725
740
726
- if (isset ($ user ['aad.isDeleted ' ]) && $ user ['aad.isDeleted ' ] == '1 ' ) {
727
- if (isset ($ aadsync ['delete ' ])) {
728
- // Check for synced user.
729
- $ sql = 'SELECT u.*
730
- FROM {user} u
731
- JOIN {local_o365_objects} obj ON obj.type = \'user \' AND obj.moodleid = u.id
732
- JOIN {auth_oidc_token} tok ON tok.userid = u.id
733
- WHERE u.username = ?
734
- AND u.mnethostid = ?
735
- AND u.deleted = ?
736
- AND u.suspended = ?
737
- AND u.auth = ? ' ;
738
- $ params = [
739
- trim (\core_text::strtolower ($ user ['userPrincipalName ' ])),
740
- $ CFG ->mnet_localhost_id ,
741
- '0 ' ,
742
- '0 ' ,
743
- 'oidc ' ,
744
- time ()
745
- ];
746
- $ synceduser = $ DB ->get_record_sql ($ sql , $ params );
747
- if (!empty ($ synceduser )) {
748
- $ synceduser ->suspended = 1 ;
749
- user_update_user ($ synceduser , false );
750
- $ this ->mtrace ($ synceduser ->username .' was marked deleted in Azure. ' );
751
- }
752
- } else {
753
- $ this ->mtrace ('User is deleted. Skipping. ' );
754
- }
755
- continue ;
756
- }
757
-
758
741
if (!isset ($ existingusers [$ user ['upnlower ' ]]) && !isset ($ existingusers [$ user ['upnsplit0 ' ]])) {
759
742
$ newmuser = $ this ->sync_new_user ($ aadsync , $ user );
760
743
} else {
@@ -805,6 +788,7 @@ public function sync_users(array $aadusers = array()) {
805
788
}
806
789
807
790
protected function sync_new_user ($ syncoptions , $ aaduserdata ) {
791
+ global $ DB ;
808
792
$ this ->mtrace ('User doesn \'t exist in Moodle ' );
809
793
810
794
$ userobjectid = (\local_o365 \rest \unified::is_configured ())
@@ -822,7 +806,15 @@ protected function sync_new_user($syncoptions, $aaduserdata) {
822
806
$ this ->mtrace ('Created user # ' .$ newmuser ->id );
823
807
}
824
808
} catch (\Exception $ e ) {
825
- $ this ->mtrace ('Could not create user " ' .$ aaduserdata ['userPrincipalName ' ].'" Reason: ' .$ e ->getMessage ());
809
+ if ($ syncoptions ['emailsync ' ]) {
810
+ if ($ DB ->record_exists ('user ' , ['username ' => $ aaduserdata ['userPrincipalName ' ]])) {
811
+ $ this ->mtrace ('Could not create user " ' .$ aaduserdata ['userPrincipalName ' ].'" Reason: user with same username, but different email already exists. ' );
812
+ } else {
813
+ $ this ->mtrace ('Could not create user with email " ' .$ aaduserdata ['userPrincipalName ' ].'" Reason: ' .$ e ->getMessage ());
814
+ }
815
+ } else {
816
+ $ this ->mtrace ('Could not create user " ' .$ aaduserdata ['userPrincipalName ' ].'" Reason: ' .$ e ->getMessage ());
817
+ }
826
818
}
827
819
828
820
// User app assignment.
@@ -953,4 +945,90 @@ protected function sync_users_matchuser($syncoptions, $aaduserdata, $existinguse
953
945
return true ;
954
946
}
955
947
}
948
+
949
+ public function delete_users () {
950
+ global $ CFG , $ DB ;
951
+ try {
952
+ $ httpclient = new \local_o365 \httpclient ();
953
+ $ clientdata = \local_o365 \oauth2 \clientdata::instance_from_oidc ();
954
+ $ resource = \local_o365 \rest \unified::get_resource ();
955
+ $ token = \local_o365 \utils::get_app_or_system_token ($ resource , $ clientdata , $ httpclient );
956
+ $ apiclient = new \local_o365 \rest \unified ($ token , $ httpclient );
957
+ } catch (\Exception $ e ) {
958
+ \local_o365 \utils::debug ('Could not construct graph api ' , 'delete_users ' , $ e );
959
+ return false ;
960
+ }
961
+
962
+ try {
963
+ $ deletedusersids = [];
964
+ $ deletedusers = $ apiclient ->list_deleted_users ();
965
+ if (is_array ($ deletedusers ) && !empty ($ deletedusers ['value ' ])) {
966
+ foreach ($ deletedusers ['value ' ] as $ deleteduser ) {
967
+ if (!empty ($ deleteduser ) && isset ($ deleteduser ['id ' ])) {
968
+ // Check for synced user.
969
+ $ sql = 'SELECT u.*
970
+ FROM {user} u
971
+ JOIN {local_o365_objects} obj ON obj.type = \'user \' AND obj.moodleid = u.id
972
+ WHERE u.mnethostid = ?
973
+ AND u.deleted = ?
974
+ AND u.suspended = ?
975
+ AND u.auth = ?
976
+ AND obj.objectid = ? ' ;
977
+ $ params = [trim (\core_text::strtolower ($ CFG ->mnet_localhost_id )),
978
+ '0 ' ,
979
+ '0 ' ,
980
+ 'oidc ' ,
981
+ $ deleteduser ['id ' ],
982
+ time ()
983
+ ];
984
+ $ synceduser = $ DB ->get_record_sql ($ sql , $ params );
985
+ if (!empty ($ synceduser )) {
986
+ $ synceduser ->suspended = 1 ;
987
+ $ DB ->update_record ('user ' , $ synceduser );
988
+ $ this ->mtrace ($ synceduser ->username . ' was deleted in Azure. ' );
989
+ }
990
+ $ deletedusersids [] = $ deleteduser ['id ' ];
991
+ }
992
+ }
993
+ }
994
+ // Check if all Moodle users with oidc authentication are still existing users in Azure
995
+ list ($ objectidsql , $ objectidparams ) = $ DB ->get_in_or_equal ($ deletedusersids , SQL_PARAMS_QM ,'param ' , false );
996
+ $ existingsql = $ sql = 'SELECT u.*, obj.objectid
997
+ FROM {user} u
998
+ JOIN {local_o365_objects} obj ON obj.type = \'user \' AND obj.moodleid = u.id
999
+ WHERE u.mnethostid = ?
1000
+ AND u.deleted = ?
1001
+ AND u.auth = ?
1002
+ AND obj.objectid ' .$ objectidsql ;
1003
+ $ existingsqlparams = array_merge ([trim (\core_text::strtolower ($ CFG ->mnet_localhost_id )),
1004
+ '0 ' ,
1005
+ 'oidc '
1006
+ ], $ objectidparams );
1007
+ $ existingusers = $ DB ->get_records_sql ($ existingsql , $ existingsqlparams );
1008
+ foreach ($ existingusers as $ existinguser ) {
1009
+ try {
1010
+ $ user = $ apiclient ->get_user ($ existinguser ->objectid );
1011
+ } catch (\Exception $ e ) {
1012
+ // Do safe delete for missing users - first suspend, on second run delete
1013
+ if ($ existinguser ->suspended ) {
1014
+ $ this ->mtrace ('Could not find suspended user ' .$ existinguser ->username .' in Azure AD. Deleting user... ' );
1015
+ $ userid = $ existinguser ->id ;
1016
+ $ objectid = $ existinguser ->objectid ;
1017
+ if (delete_user ($ existinguser )) {
1018
+ $ DB ->delete_records ('local_o365_objects ' , ['objectid ' => $ objectid ]);
1019
+ $ DB ->delete_records ('auth_oidc_token ' , ['userid ' => $ userid ]);
1020
+ }
1021
+ } else if (!$ existinguser ->suspended ) {
1022
+ $ this ->mtrace ('Could not find user ' .$ existinguser ->username .' in Azure AD. Suspending user... ' );
1023
+ $ existinguser ->suspended = 1 ;
1024
+ $ DB ->update_record ('user ' , $ existinguser );
1025
+ }
1026
+ }
1027
+ }
1028
+ return true ;
1029
+ } catch (\Exception $ e ) {
1030
+ \local_o365 \utils::debug ('Could not delete users ' , 'delete_users ' , $ e );
1031
+ return false ;
1032
+ }
1033
+ }
956
1034
}
0 commit comments