Making WordPress.org


Ignore:
Timestamp:
02/01/2022 05:14:25 AM (5 years ago)
Author:
dd32
Message:

Official WordPress Events: During the Meetup.com REST API > GraphQL migration, part of the authentication layer was deactivated, switch authentication methods.

This commit is very not-preferential-approach, but works, which is better than the code in production :)

A human is required to go through the oAuth flow, rather than letting the code perform the login, which is why this is somewhat ugly.

See https://github.com/WordPress/wordcamp.org/issues/697

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/official-wordpress-events/meetup/class-meetup-oauth2-client.php

    r9223 r11498  
    7272         * @var string
    7373         */
    74         const SITE_OPTION_KEY_OAUTH = 'meetup_oauth_token';
     74        const SITE_OPTION_KEY_OAUTH = 'meetup_access_token';
     75
     76        /**
     77         * @var string
     78         */
     79        const SITE_OPTION_KEY_AUTHORIZATION = 'meetup_oauth_authorization';
    7580
    7681        /**
     
    122127
    123128        /**
    124          * Step 1 in "Server Flow with User Credentials".
    125          *
    126          * @see https://www.meetup.com/meetup_api/auth/#oauth2servercredentials-auth
    127          *
    128          * @return array
    129          */
    130         protected function request_authorization_code() {
    131                 $authorization_code = array();
    132 
    133                 $request = array(
    134                         'client_id'     => self::CONSUMER_KEY,
    135                         'redirect_uri'  => self::REDIRECT_URI,
    136                         'response_type' => 'anonymous_code',
    137                 );
    138 
    139                 $args = array(
    140                         'headers' => $this->get_headers(),
    141                         'body'    => $request,
    142                 );
    143 
    144                 $response = $this->tenacious_remote_post( self::URL_AUTHORIZE, $args );
    145 
    146                 if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
    147                         $body = json_decode( wp_remote_retrieve_body( $response ), true );
    148 
    149                         if ( ! empty( $body['code'] ) ) {
    150                                 $authorization_code = $body;
    151                         } else {
    152                                 $this->error->add(
    153                                         'unexpected_oauth_authorization_code_response',
    154                                         'The Meetup OAuth API response did not provide the expected data.'
    155                                 );
    156                         }
    157                 } else {
    158                         $this->handle_error_response( $response );
    159                 }
    160 
    161                 return $authorization_code;
    162         }
    163 
    164         /**
    165129         * Request one of various types of tokens from the Meetup OAuth API.
    166          *
    167          * Setting $type to 'server_token' is for Step 2 in "Server Flow with User Credentials". This gets the "server
    168          * access token" which is then used to request the "oauth access token".
    169          * @see https://www.meetup.com/meetup_api/auth/#oauth2servercredentials-access
    170          *
    171          * Setting $type to 'oauth_token' is for Step 3 in "Server Flow with User Credentials". Technically in the
    172          * documentation, this token is also called an "access token", but here we're calling it the "oauth access token" to
    173          * differentiate it from the "server access token". Also, why are two separate access tokens necessary??
    174          * @see https://www.meetup.com/meetup_api/auth/#oauth2servercredentials-accesspro
    175          *
    176          * Setting $type to 'refresh_token' will request a new server access token for Step 2. This is for when the oauth
    177          * token from Step 3 is expired. The refreshed server token can then be used to obtain a new Step 3
    178          * oauth token. This skips the authorization code request (Step 1), but seems largely superfluous since a second
    179          * oauth token request must still be made with the new server token. Also, the refresh_token string used to refresh
    180          * the server token needs to come from the oauth token array, **not the server token array**. This is not what the
    181          * documentation implies. Why is this so terrible??
    182          * @see https://www.meetup.com/meetup_api/auth/#oauth2server-refresh
     130         *
     131         * Setting $type to 'access_token' is for step 2 of the oAuth flow. This takes a code that has been previously set
     132         * through a user-initiated oAuth authentication.
     133         *
     134         * Setting $type to 'refresh_token' will request a new access_token generated through the above access_token method.
     135         *
     136         * @see https://www.meetup.com/api/authentication/#p02-server-flow-section
    183137         *
    184138         * Check the `get_oauth_token` method to see how these token request flows work.
     
    197151
    198152                switch( $type ) {
    199                         case 'server_token': // Request a new server access token.
     153                        case 'access_token': // Request a new access token.
    200154                                $args = wp_parse_args( $args, array(
    201155                                        'code' => '',
     
    206160                                        'client_id'     => self::CONSUMER_KEY,
    207161                                        'client_secret' => self::CONSUMER_SECRET,
     162                                        'grant_type'    => 'authorization_code',
    208163                                        'redirect_uri'  => self::REDIRECT_URI,
    209164                                        'code'          => $args['code'],
    210                                         'grant_type'    => 'anonymous_code',
    211                                 );
     165                                );
     166                                $request_headers['Content-Type'] = 'application/x-www-form-urlencoded';
    212167                                break;
    213                         case 'refresh_token': // Refresh a server access token.
     168
     169                        case 'refresh_token': // Refresh an access token.
    214170                                $args = wp_parse_args( $args, array(
    215171                                        'refresh_token' => '',
     
    222178                                        'refresh_token' => $args['refresh_token'],
    223179                                        'grant_type'    => 'refresh_token',
    224                                 );
    225                                 break;
    226                         case 'oauth_token': // Request a new oauth token.
    227                                 $args = wp_parse_args( $args, array(
    228                                         'access_token' => '',
    229                                 ) );
    230 
    231                                 $request_url     = self::URL_OAUTH_TOKEN;
    232                                 $request_headers = $this->get_headers( $args['access_token'] );
    233                                 $request_body    = array(
    234                                         'email'    => self::EMAIL,
    235                                         'password' => self::PASSWORD,
    236180                                );
    237181                                break;
     
    281225        public function get_oauth_token() {
    282226                if ( $this->oauth_token && ! $this->is_expired_token( $this->oauth_token ) ) {
    283                         return $this->oauth_token['oauth_token'];
    284                 }
    285 
    286                 $oauth_token   = '';
    287                 $needs_caching = false;
     227                        return $this->oauth_token['access_token'];
     228                }
    288229
    289230                $token = get_site_option( self::SITE_OPTION_KEY_OAUTH, array() );
    290231
    291                 if ( ! $this->is_valid_token( $token, 'oauth_token' ) ) {
    292                         $authorization = $this->request_authorization_code(); // Step 1.
    293                         $server_token  = $this->request_token( 'server_token', $authorization ); // Step 2.
    294                         $token         = $this->request_token( 'oauth_token', $server_token ); // Step 3.
    295                         $needs_caching = true;
     232                if ( ! $this->is_valid_token( $token, 'access_token' ) ) {
     233
     234                        // At this point, we need to get a new oAuth done.
     235                        if ( empty( $_GET['code'] ) ) {
     236                                $_GET['code'] = get_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false );
     237
     238                                if ( ! $_GET['code'] ) {
     239                                        $message = sprintf(
     240                                                "Meetup.com oAuth expired. Please access the following url while logged into the %s meetup.com account: \n\n%s\n\n" .
     241                                                "For sites other than WordCamp Central, the ?code=... parameter will need to be stored on this site via wp-cli and this task run again: `wp --url=%s site option update '%s' '...'`",
     242                                                self::EMAIL,
     243                                                sprintf(
     244                                                        'https://secure.meetup.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&state=meetup-oauth',
     245                                                        self::CONSUMER_KEY,
     246                                                        self::REDIRECT_URI
     247                                                ),
     248                                                network_site_url('/'),
     249                                                self::SITE_OPTION_KEY_AUTHORIZATION
     250                                        );
     251
     252                                        if ( admin_url( '/' ) === self::REDIRECT_URI ) {
     253                                                printf( '<div class="notice notice-error"><p>%s</p></div>', nl2br( make_clickable( $message ) ) );
     254                                        }
     255
     256                                        trigger_error( $message, E_USER_WARNING );
     257
     258                                        return false;
     259                                }
     260                        }
     261
     262                        $token = $this->request_token( 'access_token', array( 'code' => $_GET['code'] ) );
     263
     264                        if ( $this->is_valid_token( $token, 'access_token' ) ) {
     265                                delete_site_option( self::SITE_OPTION_KEY_AUTHORIZATION, false );
     266                        }
     267
    296268                } elseif ( $this->is_expired_token( $token ) ) {
    297                         $server_token = $this->request_token( 'refresh_token', $token ); // Alternate for Steps 1 & 2.
    298 
    299                         // If the token is no longer valid but "looked valid" fetch a fresh one.
    300                         if ( ! $server_token && $this->error->get_error_message( 'oauth_error' ) ) {
    301                                 $this->error->remove( 'oauth_error' );
    302 
    303                                 // The token isn't valid for refreshing, request a new one.
    304                                 $authorization = $this->request_authorization_code(); // Step 1.
    305                                 $server_token  = $this->request_token( 'server_token', $authorization ); // Step 2.
    306                         }
    307 
    308                         $token         = $this->request_token( 'oauth_token', $server_token ); // Step 3.
    309                         $needs_caching = true;
    310                 }
    311 
    312                 if ( $this->is_valid_token( $token, 'oauth_token' ) ) {
    313                         $this->oauth_token = $token;
    314 
    315                         if ( $needs_caching ) {
    316                                 update_site_option( self::SITE_OPTION_KEY_OAUTH, $token );
    317                         }
    318 
    319                         $oauth_token = $this->oauth_token['oauth_token'];
    320                 }
    321 
    322                 return $oauth_token;
     269                        $token = $this->request_token( 'refresh_token', $token );
     270                }
     271
     272                if ( ! $this->is_valid_token( $token, 'access_token' ) ) {
     273                        return false;
     274                }
     275
     276                $this->oauth_token = $token;
     277
     278                update_site_option( self::SITE_OPTION_KEY_OAUTH, $this->oauth_token );
     279
     280                return $this->oauth_token['access_token'];
    323281        }
    324282
     
    333291         */
    334292        public function reset_oauth_token() {
    335                 delete_site_option( self::SITE_OPTION_KEY_OAUTH );
     293                // NO. JUST NO. Do not delete the oAuth token.
     294                // This is temporarily disabled while Meetup.com server-to-server authentication is unavailable.
     295                // delete_site_option( self::SITE_OPTION_KEY_OAUTH );
    336296
    337297                $this->oauth_token = array();
     
    350310         */
    351311        protected function is_valid_token( $token, $type ) {
    352                 $valid_types = array( 'server_token', 'refresh_token', 'oauth_token' );
     312                $valid_types = array( 'refresh_token', 'access_token' );
    353313
    354314                if ( ! is_array( $token ) || ! in_array( $type, $valid_types, true ) ) {
     
    357317
    358318                switch ( $type ) {
    359                         case 'server_token':
    360319                        case 'refresh_token':
    361320                                $required_properties = array(
     
    363322                                );
    364323                                break;
    365                         case 'oauth_token':
     324                        case 'access_token':
    366325                        default:
    367326                                $required_properties = array(
    368                                         'oauth_token'   => '',
     327                                        'access_token'   => '',
    369328                                        'refresh_token' => '',
    370329                                        'expires_in'    => '',
Note: See TracChangeset for help on using the changeset viewer.