signature = $signature; $this->baseApiUri = $baseApiUri; $this->signature->setHashingAlgorithm($this->getSignatureMethod()); } /** * {@inheritDoc} */ public function requestRequestToken() { $authorizationHeader = array('Authorization' => $this->buildAuthorizationHeaderForTokenRequest()); $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders()); $responseBody = $this->httpClient->retrieveResponse($this->getRequestTokenEndpoint(), array(), $headers); $token = $this->parseRequestTokenResponse($responseBody); $this->storage->storeAccessToken($this->service(), $token); return $token; } /** * {@inheritdoc} */ public function getAuthorizationUri(array $additionalParameters = array()) { // Build the url $url = clone $this->getAuthorizationEndpoint(); foreach ($additionalParameters as $key => $val) { $url->addToQuery($key, $val); } return $url; } /** * {@inheritDoc} */ public function requestAccessToken($token, $verifier, $tokenSecret = null) { if (is_null($tokenSecret)) { $storedRequestToken = $this->storage->retrieveAccessToken($this->service()); $tokenSecret = $storedRequestToken->getRequestTokenSecret(); } $this->signature->setTokenSecret($tokenSecret); $bodyParams = array( 'oauth_verifier' => $verifier, ); $authorizationHeader = array( 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest( 'POST', $this->getAccessTokenEndpoint(), $this->storage->retrieveAccessToken($this->service()), $bodyParams ) ); $headers = array_merge($authorizationHeader, $this->getExtraOAuthHeaders()); $responseBody = $this->httpClient->retrieveResponse($this->getAccessTokenEndpoint(), $bodyParams, $headers); $token = $this->parseAccessTokenResponse($responseBody); $this->storage->storeAccessToken($this->service(), $token); return $token; } /** * Sends an authenticated API request to the path provided. * If the path provided is not an absolute URI, the base API Uri (must be passed into constructor) will be used. * * @param string|UriInterface $path * @param string $method HTTP method * @param array $body Request body if applicable (key/value pairs) * @param array $extraHeaders Extra headers if applicable. * These will override service-specific any defaults. * * @return string */ public function request($path, $method = 'GET', $body = null, array $extraHeaders = array()) { $uri = $this->determineRequestUriFromPath($path, $this->baseApiUri); /** @var $token StdOAuth1Token */ $token = $this->storage->retrieveAccessToken($this->service()); $extraHeaders = array_merge($this->getExtraApiHeaders(), $extraHeaders); $authorizationHeader = array( 'Authorization' => $this->buildAuthorizationHeaderForAPIRequest($method, $uri, $token, $body) ); $headers = array_merge($authorizationHeader, $extraHeaders); return $this->httpClient->retrieveResponse($uri, $body, $headers, $method); } /** * Return any additional headers always needed for this service implementation's OAuth calls. * * @return array */ protected function getExtraOAuthHeaders() { return array(); } /** * Return any additional headers always needed for this service implementation's API calls. * * @return array */ protected function getExtraApiHeaders() { return array(); } /** * Builds the authorization header for getting an access or request token. * * @param array $extraParameters * * @return string */ protected function buildAuthorizationHeaderForTokenRequest(array $extraParameters = array()) { $parameters = $this->getBasicAuthorizationHeaderInfo(); $parameters = array_merge($parameters, $extraParameters); $parameters['oauth_signature'] = $this->signature->getSignature( $this->getRequestTokenEndpoint(), $parameters, 'POST' ); $authorizationHeader = 'OAuth '; $delimiter = ''; foreach ($parameters as $key => $value) { $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"'; $delimiter = ', '; } return $authorizationHeader; } /** * Builds the authorization header for an authenticated API request * * @param string $method * @param UriInterface $uri The uri the request is headed * @param TokenInterface $token * @param array $bodyParams Request body if applicable (key/value pairs) * * @return string */ protected function buildAuthorizationHeaderForAPIRequest( $method, UriInterface $uri, TokenInterface $token, $bodyParams = null ) { $this->signature->setTokenSecret($token->getAccessTokenSecret()); $parameters = $this->getBasicAuthorizationHeaderInfo(); if (isset($parameters['oauth_callback'])) { unset($parameters['oauth_callback']); } $parameters = array_merge($parameters, array('oauth_token' => $token->getAccessToken())); $parameters = (is_array($bodyParams)) ? array_merge($parameters, $bodyParams) : $parameters; $parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method); $authorizationHeader = 'OAuth '; $delimiter = ''; foreach ($parameters as $key => $value) { $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"'; $delimiter = ', '; } return $authorizationHeader; } /** * Builds the authorization header array. * * @return array */ protected function getBasicAuthorizationHeaderInfo() { $dateTime = new \DateTime(); $headerParameters = array( 'oauth_callback' => $this->credentials->getCallbackUrl(), 'oauth_consumer_key' => $this->credentials->getConsumerId(), 'oauth_nonce' => $this->generateNonce(), 'oauth_signature_method' => $this->getSignatureMethod(), 'oauth_timestamp' => $dateTime->format('U'), 'oauth_version' => $this->getVersion(), ); return $headerParameters; } /** * Pseudo random string generator used to build a unique string to sign each request * * @param int $length * * @return string */ protected function generateNonce($length = 32) { $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; $nonce = ''; $maxRand = strlen($characters)-1; for ($i = 0; $i < $length; $i++) { $nonce.= $characters[rand(0, $maxRand)]; } return $nonce; } /** * @return string */ protected function getSignatureMethod() { return 'HMAC-SHA1'; } /** * This returns the version used in the authorization header of the requests * * @return string */ protected function getVersion() { return '1.0'; } /** * Parses the request token response and returns a TokenInterface. * This is only needed to verify the `oauth_callback_confirmed` parameter. The actual * parsing logic is contained in the access token parser. * * @abstract * * @param string $responseBody * * @return TokenInterface * * @throws TokenResponseException */ abstract protected function parseRequestTokenResponse($responseBody); /** * Parses the access token response and returns a TokenInterface. * * @abstract * * @param string $responseBody * * @return TokenInterface * * @throws TokenResponseException */ abstract protected function parseAccessTokenResponse($responseBody); }