55Plugin URI: http://github.com/psignoret/aad-sso-wordpress
66Description: Allows you to use your organization's Azure Active Directory user accounts to log in to WordPress. If your organization is using Office 365, your user accounts are already in Azure Active Directory. This plugin uses OAuth 2.0 to authenticate users, and the Azure Active Directory Graph to get group membership and other details.
77Author: Philippe Signoret
8- Version: 0.6.1
8+ Version: 0.6.2
99Author URI: https://www.psignoret.com/
1010Text Domain: aad-sso-wordpress
1111Domain Path: /languages/
1717define ( 'AADSSO_PLUGIN_URL ' , plugin_dir_url ( __FILE__ ) );
1818define ( 'AADSSO_PLUGIN_DIR ' , plugin_dir_path ( __FILE__ ) );
1919
20+ defined ( 'AADSSO_DEBUG ' ) or define ( 'AADSSO_DEBUG ' , FALSE );
21+ defined ( 'AADSSO_DEBUG_LEVEL ' ) or define ( 'AADSSO_DEBUG_LEVEL ' , 0 );
22+
2023// Proxy to be used for calls, should be useful for tracing with Fiddler
2124// BUGBUG: Doesn't actually work, at least not with WP running on WAMP stack
2225//define( 'WP_PROXY_HOST', '127.0.0.1' );
@@ -278,7 +281,8 @@ function authenticate( $user, $username, $password ) {
278281 $ antiforgery_id
279282 );
280283
281- AADSSO ::debug_log ( json_encode ( $ jwt ) );
284+ AADSSO ::debug_log ( 'id_token: iss: \'' . $ jwt ->iss . '\', oid: \'' . $ jwt ->oid , 10 );
285+ AADSSO ::debug_log ( json_encode ( $ jwt ), 50 );
282286
283287 } catch ( Exception $ e ) {
284288 return new WP_Error (
@@ -338,22 +342,18 @@ function get_wp_user_from_aad_user( $jwt ) {
338342 $ unique_name = isset ( $ jwt ->upn ) ? $ jwt ->upn : ( isset ( $ jwt ->unique_name ) ? $ jwt ->unique_name : null );
339343 if ( null === $ unique_name ) {
340344 return new WP_Error (
341- 'unique_name_not_found ' ,
342- __ ( 'ERROR: Neither \'upn \' nor \'unique_name \' claims not found in ID Token. ' ,
343- 'aad-sso-wordpress ' )
344- );
345+ 'unique_name_not_found ' ,
346+ __ ( 'ERROR: Neither \'upn \' nor \'unique_name \' claims not found in ID Token. ' ,
347+ 'aad-sso-wordpress ' )
348+ );
345349 }
346350
347351 $ user = get_user_by ( $ this ->settings ->field_to_match_to_upn , $ unique_name );
348352
349- if ( true === $ this ->settings ->match_on_upn_alias ) {
350- if ( ! is_a ( $ user , 'WP_User ' ) ) {
351- $ username = explode ( sprintf ( '@%s ' , $ this ->settings ->org_domain_hint ), $ unique_name );
352- $ user = get_user_by ( $ this ->settings ->field_to_match_to_upn , $ username [0 ] );
353- }
354- }
355-
356- if ( ! is_a ( $ user , 'WP_User ' ) ) {
353+ if ( is_a ( $ user , 'WP_User ' ) ) {
354+ AADSSO ::debug_log ( sprintf (
355+ 'Matched Azure AD user [%s] to existing WordPress user [%s]. ' , $ unique_name , $ user ->ID ), 10 );
356+ } else {
357357
358358 // Since the user was authenticated with AAD, but not found in WordPress,
359359 // need to decide whether to create a new user in WP on-the-fly, or to stop here.
@@ -372,20 +372,19 @@ function get_wp_user_from_aad_user( $jwt ) {
372372
373373 $ new_user_id = wp_insert_user ( $ userdata );
374374
375- if (is_wp_error ( $ new_user_id ) ) {
375+ if ( is_wp_error ( $ new_user_id ) ) {
376376 // The user was authenticated, but not found in WP and auto-provisioning is disabled
377377 return new WP_Error (
378378 'user_not_registered ' ,
379379 sprintf (
380- __ ( 'ERROR: Cannot create user %s . ' , 'aad-sso-wordpress ' ),
380+ __ ( 'ERROR: Error creating user \' %s \' . ' , 'aad-sso-wordpress ' ),
381381 $ unique_name
382382 )
383383 );
384384 }
385385 else
386386 {
387387 AADSSO ::debug_log ( 'Created new user: \'' . $ unique_name . '\', user id ' . $ new_user_id . '. ' );
388-
389388 $ user = new WP_User ( $ new_user_id );
390389 }
391390 } else {
@@ -394,8 +393,9 @@ function get_wp_user_from_aad_user( $jwt ) {
394393 return new WP_Error (
395394 'user_not_registered ' ,
396395 sprintf (
397- __ ( 'ERROR: The authenticated user %s is not a registered user in this blog. ' , 'aad-sso-wordpress ' ),
398- $ jwt ->upn
396+ __ ( 'ERROR: The authenticated user \'%s \' is not a registered user in this site. ' ,
397+ 'aad-sso-wordpress ' ),
398+ $ unique_name
399399 )
400400 );
401401 }
@@ -411,47 +411,70 @@ function get_wp_user_from_aad_user( $jwt ) {
411411 * @param string $aad_user_id The AAD object id of the user
412412 * @param string $aad_tenant_id The AAD directory tenant ID
413413 *
414- * @return WP_User|WP_Error Return the WP_User with updated rols , or WP_Error if failed.
414+ * @return WP_User|WP_Error Return the WP_User with updated roles , or WP_Error if failed.
415415 */
416416 function update_wp_user_roles ( $ user , $ aad_user_id , $ aad_tenant_id ) {
417417
418- // Pass the settings to GraphHelper
418+ // TODO: Cleaner (but still lazy) initialization of GraphHelper
419419 AADSSO_GraphHelper::$ settings = $ this ->settings ;
420420 AADSSO_GraphHelper::$ tenant_id = $ aad_tenant_id ;
421421
422422 // Of the AAD groups defined in the settings, get only those where the user is a member
423423 $ group_ids = array_keys ( $ this ->settings ->aad_group_to_wp_role_map );
424424 $ group_memberships = AADSSO_GraphHelper::user_check_member_groups ( $ aad_user_id , $ group_ids );
425+
426+ // Check for errors in the group membership check response
427+ if ( isset ( $ group_memberships ->value ) ) {
428+ AADSSO ::debug_log ( sprintf (
429+ 'Out of [%s], user \'%s \' is a member of [%s] ' ,
430+ implode ( ', ' , $ group_ids ), $ aad_user_id , implode ( ', ' , $ group_memberships ->value ) ), 20
431+ );
432+ } elseif ( isset ( $ group_memberships ->{'odata.error ' } ) ) {
433+ AADSSO ::debug_log ( 'Error when checking group membership: ' . json_encode ( $ group_memberships ) );
434+ return new WP_Error (
435+ 'error_checking_group_membership ' ,
436+ sprintf (
437+ __ ( 'ERROR: Unable to check group membership in Azure AD: <b>%s</b>. ' ,
438+ 'aad-sso-wordpress ' ), $ group_memberships ->{'odata.error ' }->code )
439+ );
440+ } else {
441+ AADSSO ::debug_log ( 'Unexpected response to checkMemberGroups: ' . json_encode ( $ group_memberships ) );
442+ return new WP_Error (
443+ 'unexpected_response_to_checkMemberGroups ' ,
444+ __ ( 'ERROR: Unexpected response when checking group membership in Azure AD. ' ,
445+ 'aad-sso-wordpress ' )
446+ );
447+ }
425448
426449 // Determine which WordPress role the AAD group corresponds to.
427- // TODO: Check for error in the group membership response
428- $ role_to_set = array ();
450+ $ roles_to_set = array ();
429451
430452 if ( ! empty ( $ group_memberships ->value ) ) {
431453 foreach ( $ this ->settings ->aad_group_to_wp_role_map as $ aad_group => $ wp_role ) {
432454 if ( in_array ( $ aad_group , $ group_memberships ->value ) ) {
433- array_push ( $ role_to_set , $ wp_role );
455+ array_push ( $ roles_to_set , $ wp_role );
434456 }
435457 }
436458 }
437459
438- if ( ! empty ( $ role_to_set ) ) {
439- $ user ->set_role ("" );
440- foreach ( $ role_to_set as $ role ){
460+ if ( ! empty ( $ roles_to_set ) ) {
461+ $ user ->set_role ( '' );
462+ foreach ( $ roles_to_set as $ role ) {
441463 $ user ->add_role ( $ role );
442464 }
443- }
444- else if ( null != $ this ->settings ->default_wp_role || "" != $ this ->settings ->default_wp_role ){
465+ AADSSO ::debug_log ( sprintf (
466+ 'Set roles [%s] for user [%s]. ' , implode ( ', ' , $ roles_to_set ), $ user ->ID ), 10 );
467+ } else if ( ! empty ( $ this ->settings ->default_wp_role ) ) {
445468 $ user ->set_role ( $ this ->settings ->default_wp_role );
446- }
447- else {
448- return new WP_Error (
449- 'user_not_member_of_required_group ' ,
450- sprintf (
451- __ ( 'ERROR: AAD user %s is not a member of any group granting a role. ' , 'aad-sso-wordpress ' ),
452- $ aad_user_id
453- )
469+ AADSSO ::debug_log ( sprintf (
470+ 'Set default role [%s] for user [%s]. ' , $ this ->settings ->default_wp_role , $ user ->ID ), 10 );
471+ } else {
472+ $ error_message = sprintf (
473+ __ ( 'ERROR: Azure AD user %s is not a member of any group granting a role. ' , 'aad-sso-wordpress ' ),
474+ $ aad_user_id
454475 );
476+ AADSSO ::debug_log ( $ error_message , 10 );
477+ return new WP_Error ( 'user_not_member_of_required_group ' , $ error_message );
455478 }
456479
457480 return $ user ;
@@ -574,14 +597,21 @@ function print_login_link() {
574597 );
575598 }
576599
577- public static function debug_log ( $ message ) {
578- if ( defined ('AADSSO_DEBUG ' ) && true === AADSSO_DEBUG ) {
579- if ( strpos ( $ message , "\n" ) === false ) {
600+ /**
601+ * Emits debug details to the logs. The higher the level, the more verbose.
602+ *
603+ * If there are multiple lines in the message, they will each be emitted as a log line.
604+ */
605+ public static function debug_log ( $ message , $ level = 0 ) {
606+
607+ // AADSSO_DEBUG and AADSSO_DEBUG_LEVEL are already defined.
608+ if ( AADSSO_DEBUG && AADSSO_DEBUG_LEVEL >= $ level ) {
609+ if ( FALSE === strpos ( $ message , "\n" ) ) {
580610 error_log ( 'AADSSO: ' . $ message );
581611 } else {
582612 $ lines = explode ( "\n" , str_replace ( "\r\n" , "\n" , $ message ) );
583613 foreach ( $ lines as $ line ) {
584- AADSSO ::debug_log ( $ line );
614+ AADSSO ::debug_log ( $ line, $ level );
585615 }
586616 }
587617 }
@@ -590,20 +620,15 @@ public static function debug_log( $message ) {
590620 /**
591621 * Prints the debug backtrace using this class' debug_log function.
592622 */
593- public static function debug_print_backtrace () {
623+ public static function debug_print_backtrace ( $ level = 10 ) {
594624 ob_start ();
595625 debug_print_backtrace ();
596626 $ trace = ob_get_contents ();
597627 ob_end_clean ();
598- self ::debug_log ( $ trace );
628+ self ::debug_log ( $ trace, $ level );
599629 }
600630}
601631
602- // Load settings JSON contents from DB and initialize the plugin
603- $ aadsso_settings_instance = AADSSO_Settings::init ();
604- $ aadsso = AADSSO ::get_instance ( $ aadsso_settings_instance );
605-
606-
607632/*** Utility functions ***/
608633
609634if ( ! function_exists ( 'com_create_guid ' ) ) {
@@ -626,3 +651,7 @@ function com_create_guid() {
626651 return $ uuid ;
627652 }
628653}
654+
655+ // Load settings JSON contents from DB and initialize the plugin
656+ $ aadsso_settings_instance = AADSSO_Settings::init ();
657+ $ aadsso = AADSSO ::get_instance ( $ aadsso_settings_instance , com_create_guid () );
0 commit comments