      1: <?php
      2: /**
      3:  *
      4:  */
      5: abstract class RESTian_Auth_Provider_Base {
      6:
      7:   /**
      8:    * @var RESTian_Client
      9:    */
     10:   var $api;
     11:
     12:   /**
     13:    * @var string RESTian-specific authorization type identifier, like 'basic_http', etc.
     14:    */
     15:   var $auth_type;
     16:
     17:   /**
     18:    * @var string To contain something like '1.0a', to be set by subclass if needed.
     19:    */
     20:   var $auth_version;
     21:
     22:   /**
     23:    * @var string Allows auth provider to set a user readable message
     24:    */
     25:   var $message;
     26:
     27:   /**
     28:    * @param RESTian_Client $api
     29:    */
     30:   function __construct( $api ) {
     31:     $this->api = $api;
     32:   }
     33:
     34:   /**
     35:    * Allow auth provider to process credentials
     36:    *
     37:    * @param array $credentials
     38:    * @return array
     39:    */
     40:   function prepare_credentials( $credentials ) {
     41:     return $credentials;
     42:   }
     43:
     44:   /**
     45:    * Allow auth provider to process grant
     46:    *
     47:    * @param array $grant
     48:    * @param array $credentials
     49:    * @return array
     50:    */
     51:   function prepare_grant( $grant, $credentials ) {
     52:     return $grant;
     53:   }
     54:
     55:   /**
     56:    * @return array
     57:    */
     58:   function get_new_credentials() {
     59:     return array();
     60:   }
     61:
     62:   /**
     63:    * @return array
     64:    */
     65:   function get_new_grant() {
     66:     return array();
     67:   }
     68:
     69:   /**
     70:    * Determine if provided credentials represent a viable set of credentials
     71:    *
     72:    * Default behavior ensures that all credential elements exist, i.e. if username and password are required
     73:    * this code ensures both username and password have a value. Subclasses can add or relax requirements using
     74:    * their own algorithms as required.
     75:    *
     76:    * @param array $credentials
     77:    * @return bool
     78:    */
     79:   function is_credentials( $credentials ) {
     80:     $is_credentials = true;
     81:     if ( ! $this->_has_required( $this->get_new_credentials(), $credentials ) ) {
     82:       $is_credentials = false;
     83:       $this->message = 'The required credentials were not provided.';
     84:     }
     85:     return $is_credentials;
     86:   }
     87:
     88:   /**
     89:    * Determine if provided grant represents a viable grant
     90:    *
     91:    * Default behavior ensures that all grant elements exist, i.e. if access_token and refresh_token are required
     92:    * this code ensures both access_token and refresh_token have a value. Subclasses can add or relax requirements
     93:    * using their own algorithms as required.
     94:    *
     95:    * @param array $grant
     96:    * @return bool
     97:    */
     98:   function is_grant( $grant ) {
     99:     return $this->_has_required( $this->get_new_grant(), $grant );
    100:   }
    101:
    102:   /**
    103:    * Extract grant from the passed $auth_settings.
    104:    *
    105:    * @param array $auth_settings
    106:    * @return array
    107:    */
    108:   function extract_grant( $auth_settings ) {
    109:     return array_intersect_key( $auth_settings, $this->get_new_grant() );
    110:   }
    111:
    112:   /**
    113:    * Extract credentials from the passed $auth_settings.
    114:    *
    115:    * @param array $auth_settings
    116:    * @return array
    117:    */
    118:   function extract_credentials( $auth_settings ) {
    119:     return array_intersect_key( $auth_settings, $this->get_new_credentials() );
    120:   }
    121:
    122:
    123:   /**
    124:    * Test to see if the request has prerequisites required to authenticate, i.e. credentials.
    125:    *
    126:    * Defaults to making sure that the request has valid credentials; subclasses can modify as required.
    127:    *
    128:    * @param array $credentials
    129:    * @return bool
    130:    */
    131:   function has_prerequisites( $credentials ) {
    132:     return $this->is_credentials( $credentials );
    133:   }
    134:
    135:   /**
    136:    * Allows an auth provider to decorate a RESTian_Request prior to $request->make_request(), as required.
    137:    *
    138:    * @param RESTian_Request $request
    139:    */
    140:   function prepare_request( $request ) {
    141:   }
    142:
    143:   /**
    144:    * Allows an auth provider to handle a response; returns true if handled, false otherwise.
    145:    *
    146:    * The auth provider does not have to handle every response.
    147:    *
    148:    * @param RESTian_Response $response
    149:    * @return bool
    150:    */
    151:   function handle_response( $response ) {
    152:     return false;
    153:   }
    154:
    155:   /**
    156:    * Takes the response and capture the grant in the format $this->is_grant() will validate
    157:    *
    158:    * @param RESTian_Response $response
    159:    */
    160:   function capture_grant( $response ) {
    161:     $response->grant = array( 'authenticated' => $response->authenticated );
    162:   }
    163:
    164:   /**
    165:    * Tests a RESTian_Response returning true if the response was authenticated, false otherwise.
    166:    *
    167:    * Default is an HTTP 200 or 204 status code; subclasses can modify as required.
    168:    *
    169:    * @see: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success
    170:    *
    171:    * @param RESTian_Response $response
    172:    * @return bool
    173:    */
    174:   function authenticated( $response ) {
    175:     return preg_match( '#^(200|204)$#', $response->status_code );
    176:   }
    177:
    178:   /**
    179:    * Return an error message
    180:    *
    181:    * @param string $code
    182:    * @return string
    183:    */
    184:   function get_error_message( $code ) {
    185:     switch ( $code ) {
    186:       case 'NO_AUTH':
    187:         $message = 'Either the username and/or password were not provided. This is likely a programmer error. Please contact the site\'s owner.';
    188:         break;
    189:
    190:       case 'BAD_AUTH':
    191:         $message = "Your username and password combination were not recognized by the {$this->api->api_name}.";
    192:         break;
    193:
    194:       default:
    195:         $message = false;
    196:         break;
    197:     }
    198:     return $message;
    199:   }
    200:
    201:   /**
    202:    * Tests an array to ensure it has all required elements given a pattern array.
    203:    *
    204:    * @examples:
    205:    *
    206:    *    $pattern = array( 'a' => '', 'b' => '', 'c' => '' );
    207:    *    $array = array( 'a' => 'foo', 'b' => 'bar', 'd' => 'baz' );
    208:    *    $this->_has_required( $pattern, $array ) // returns false because !isset($array['c'])
    209:    *
    210:    *    $pattern = array( 'a' => '', 'b' => '', 'c' => '' );
    211:    *    $array = array( 'a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'd' => 'bezong' );
    212:    *    $this->_has_required( $pattern, $array ) // returns true because !isset($array['d']) is irrelevant.
    213:    *
    214:    * @param array $pattern_array
    215:    * @param array $array_to_test
    216:    *
    217:    * @return bool
    218:    */
    219:   protected function _has_required( $pattern_array, $array_to_test ) {
    220:     $has_required = true;
    221:     foreach( array_keys( $pattern_array ) as $key ) {
    222:       if ( empty( $array_to_test[$key] ) ) {
    223:         $has_required = false;
    224:         break;
    225:       }
    226:     }
    227:     return $has_required;
    228:   }
    229: }
    230: