Overview

Namespaces

  • Contrib
    • Bundle
      • CoverallsBundle
        • Console
        • Entity
      • CoverallsV1Bundle
        • Api
        • Collector
        • Command
        • Config
        • Entity
          • Git
    • Component
      • File
      • Log
      • System
        • Git
  • Guzzle
    • Batch
      • Exception
    • Cache
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
      • QueryAggregator
    • Inflection
    • Iterator
    • Log
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Async
      • Backoff
      • Cache
      • Cookie
        • CookieJar
        • Exception
      • CurlAuth
      • ErrorResponse
        • Exception
      • History
      • Log
      • Md5
      • Mock
      • Oauth
    • Service
      • Builder
      • Command
        • Factory
        • LocationVisitor
          • Request
          • Response
      • Description
      • Exception
      • Resource
    • Stream
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Config
        • Definition
          • Builder
          • Exception
        • Exception
        • Loader
        • Resource
        • Util
      • Console
        • Command
        • Formatter
        • Helper
        • Input
        • Output
        • Tester
      • EventDispatcher
        • Debug
      • Finder
        • Adapter
        • Comparator
        • Exception
        • Expression
        • Iterator
        • Shell
      • Stopwatch
      • Yaml
        • Exception

Classes

  • OauthPlugin
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: namespace Guzzle\Plugin\Oauth;
  4: 
  5: use Guzzle\Common\Event;
  6: use Guzzle\Common\Collection;
  7: use Guzzle\Http\Message\RequestInterface;
  8: use Guzzle\Http\Message\EntityEnclosingRequestInterface;
  9: use Guzzle\Http\QueryString;
 10: use Guzzle\Http\Url;
 11: use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 12: 
 13: /**
 14:  * OAuth signing plugin
 15:  * @link http://oauth.net/core/1.0/#rfc.section.9.1.1
 16:  */
 17: class OauthPlugin implements EventSubscriberInterface
 18: {
 19:     /**
 20:      * @var Collection Configuration settings
 21:      */
 22:     protected $config;
 23: 
 24:     /**
 25:      * Create a new OAuth 1.0 plugin
 26:      *
 27:      * @param array $config Configuration array containing these parameters:
 28:      *     - string 'callback'             OAuth callback
 29:      *     - string 'consumer_key'         Consumer key
 30:      *     - string 'consumer_secret'      Consumer secret
 31:      *     - string 'token'                Token
 32:      *     - string 'token_secret'         Token secret
 33:      *     - string 'verifier'             OAuth verifier.
 34:      *     - string 'version'              OAuth version.  Defaults to 1.0
 35:      *     - string 'signature_method'     Custom signature method
 36:      *     - bool   'disable_post_params'  Set to true to prevent POST parameters from being signed
 37:      *     - array|Closure 'signature_callback' Custom signature callback that accepts a string to sign and a signing key
 38:      */
 39:     public function __construct($config)
 40:     {
 41:         $this->config = Collection::fromConfig($config, array(
 42:             'version' => '1.0',
 43:             'consumer_key' => 'anonymous',
 44:             'consumer_secret' => 'anonymous',
 45:             'signature_method' => 'HMAC-SHA1',
 46:             'signature_callback' => function($stringToSign, $key) {
 47:                 return hash_hmac('sha1', $stringToSign, $key, true);
 48:             }
 49:         ), array(
 50:             'signature_method', 'signature_callback', 'version',
 51:             'consumer_key', 'consumer_secret'
 52:         ));
 53:     }
 54: 
 55:     /**
 56:      * {@inheritdoc}
 57:      */
 58:     public static function getSubscribedEvents()
 59:     {
 60:         return array(
 61:             'request.before_send' => array('onRequestBeforeSend', -1000)
 62:         );
 63:     }
 64: 
 65:     /**
 66:      * Request before-send event handler
 67:      *
 68:      * @param Event $event Event received
 69:      * @return array
 70:      */
 71:     public function onRequestBeforeSend(Event $event)
 72:     {
 73:         $timestamp = $this->getTimestamp($event);
 74:         $request = $event['request'];
 75:         $nonce = $this->generateNonce($request);
 76: 
 77:         $authorizationParams = array(
 78:             'oauth_callback'         => $this->config['callback'],
 79:             'oauth_consumer_key'     => $this->config['consumer_key'],
 80:             'oauth_nonce'            => $nonce,
 81:             'oauth_signature'        => $this->getSignature($request, $timestamp, $nonce),
 82:             'oauth_signature_method' => $this->config['signature_method'],
 83:             'oauth_timestamp'        => $timestamp,
 84:             'oauth_token'            => $this->config['token'],
 85:             'oauth_verifier'         => $this->config['verifier'],
 86:             'oauth_version'          => $this->config['version'],
 87:         );
 88: 
 89:         $request->setHeader(
 90:             'Authorization',
 91:             $this->buildAuthorizationHeader($authorizationParams)
 92:         );
 93: 
 94:         return $authorizationParams;
 95:     }
 96: 
 97:     /**
 98:      * Builds the Authorization header for a request
 99:      *
100:      * @param array $authorizationParams Associative array of authorization parameters
101:      *
102:      * @return string
103:      */
104:     private function buildAuthorizationHeader($authorizationParams)
105:     {
106:         $authorizationString = 'OAuth ';
107:         foreach ($authorizationParams as $key => $val) {
108:             if ($val) {
109:                 $authorizationString .= $key . '="' . urlencode($val) . '", ';
110:             }
111:         }
112: 
113:         return substr($authorizationString, 0, -2);
114:     }
115: 
116:     /**
117:      * Calculate signature for request
118:      *
119:      * @param RequestInterface $request   Request to generate a signature for
120:      * @param integer          $timestamp Timestamp to use for nonce
121:      * @param string           $nonce
122:      *
123:      * @return string
124:      */
125:     public function getSignature(RequestInterface $request, $timestamp, $nonce)
126:     {
127:         $string = $this->getStringToSign($request, $timestamp, $nonce);
128:         $key = urlencode($this->config['consumer_secret']) . '&' . urlencode($this->config['token_secret']);
129: 
130:         return base64_encode(call_user_func($this->config['signature_callback'], $string, $key));
131:     }
132: 
133:     /**
134:      * Calculate string to sign
135:      *
136:      * @param RequestInterface $request   Request to generate a signature for
137:      * @param int              $timestamp Timestamp to use for nonce
138:      * @param string           $nonce
139:      *
140:      * @return string
141:      */
142:     public function getStringToSign(RequestInterface $request, $timestamp, $nonce)
143:     {
144:         $params = $this->getParamsToSign($request, $timestamp, $nonce);
145: 
146:         // Convert booleans to strings.
147:         $params = $this->prepareParameters($params);
148: 
149:         // Build signing string from combined params
150:         $parameterString = new QueryString($params);
151: 
152:         $url = Url::factory($request->getUrl())->setQuery('')->setFragment(null);
153: 
154:         return strtoupper($request->getMethod()) . '&'
155:              . rawurlencode($url) . '&'
156:              . rawurlencode((string) $parameterString);
157:     }
158: 
159:     /**
160:      * Parameters sorted and filtered in order to properly sign a request
161:      *
162:      * @param RequestInterface $request   Request to generate a signature for
163:      * @param integer          $timestamp Timestamp to use for nonce
164:      * @param string           $nonce
165:      *
166:      * @return array
167:      */
168:     public function getParamsToSign(RequestInterface $request, $timestamp, $nonce)
169:     {
170:         $params = new Collection(array(
171:             'oauth_callback'         => $this->config['callback'],
172:             'oauth_consumer_key'     => $this->config['consumer_key'],
173:             'oauth_nonce'            => $nonce,
174:             'oauth_signature_method' => $this->config['signature_method'],
175:             'oauth_timestamp'        => $timestamp,
176:             'oauth_token'            => $this->config['token'],
177:             'oauth_verifier'         => $this->config['verifier'],
178:             'oauth_version'          => $this->config['version']
179:         ));
180: 
181:         // Add query string parameters
182:         $params->merge($request->getQuery());
183: 
184:         // Add POST fields to signing string if required
185:         if ($this->shouldPostFieldsBeSigned($request))
186:         {
187:             $params->merge($request->getPostFields());
188:         }
189: 
190:         // Sort params
191:         $params = $params->getAll();
192:         ksort($params);
193: 
194:         return $params;
195:     }
196: 
197:     /**
198:      * Decide whether the post fields should be added to the base string that Oauth signs.
199:      * This implementation is correct. Non-conformant APIs may require that this method be
200:      * overwritten e.g. the Flickr API incorrectly adds the post fields when the Content-Type
201:      * is 'application/x-www-form-urlencoded'
202:      *
203:      * @param $request
204:      * @return bool Whether the post fields should be signed or not
205:      */
206:     public function shouldPostFieldsBeSigned($request)
207:     {
208:         if (!$this->config->get('disable_post_params') &&
209:             $request instanceof EntityEnclosingRequestInterface &&
210:             false !== strpos($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded'))
211:         {
212:             return true;
213:         }
214: 
215:         return false;
216:     }
217: 
218:     /**
219:      * Returns a Nonce Based on the unique id and URL. This will allow for multiple requests in parallel with the same
220:      * exact timestamp to use separate nonce's.
221:      *
222:      * @param RequestInterface $request Request to generate a nonce for
223:      *
224:      * @return string
225:      */
226:     public function generateNonce(RequestInterface $request)
227:     {
228:         return sha1(uniqid('', true) . $request->getUrl());
229:     }
230: 
231:     /**
232:      * Gets timestamp from event or create new timestamp
233:      *
234:      * @param Event $event Event containing contextual information
235:      *
236:      * @return int
237:      */
238:     public function getTimestamp(Event $event)
239:     {
240:        return $event['timestamp'] ?: time();
241:     }
242: 
243:     /**
244:      * Convert booleans to strings, removed unset parameters, and sorts the array
245:      *
246:      * @param array $data Data array
247:      *
248:      * @return array
249:      */
250:     protected function prepareParameters($data)
251:     {
252:         ksort($data);
253:         foreach ($data as $key => &$value) {
254:             switch (gettype($value)) {
255:                 case 'NULL':
256:                     unset($data[$key]);
257:                     break;
258:                 case 'array':
259:                     $data[$key] = self::prepareParameters($value);
260:                     break;
261:                 case 'boolean':
262:                     $data[$key] = $value ? 'true' : 'false';
263:                     break;
264:             }
265:         }
266: 
267:         return $data;
268:     }
269: }
270: 
php-coveralls API documentation generated by ApiGen 2.8.0