[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/externals/twilio-php/Services/Twilio/ -> Capability.php (source)

   1  <?php
   2  
   3  /**
   4   * Twilio Capability Token generator
   5   *
   6   * @category Services
   7   * @package  Services_Twilio
   8   * @author Jeff Lindsay <[email protected]>
   9   * @license  http://creativecommons.org/licenses/MIT/ MIT
  10   */
  11  class Services_Twilio_Capability
  12  {
  13      public $accountSid;
  14      public $authToken;
  15      public $scopes;
  16  
  17      /**
  18       * Create a new TwilioCapability with zero permissions. Next steps are to
  19       * grant access to resources by configuring this token through the
  20       * functions allowXXXX.
  21       *
  22       * @param $accountSid the account sid to which this token is granted access
  23       * @param $authToken the secret key used to sign the token. Note, this auth
  24       *        token is not visible to the user of the token.
  25       */
  26      public function __construct($accountSid, $authToken)
  27      {
  28          $this->accountSid = $accountSid;
  29          $this->authToken = $authToken;
  30          $this->scopes = array();
  31          $this->clientName = false;
  32      }
  33  
  34      /**
  35       * If the user of this token should be allowed to accept incoming
  36       * connections then configure the TwilioCapability through this method and
  37       * specify the client name.
  38       *
  39       * @param $clientName
  40       */
  41      public function allowClientIncoming($clientName)
  42      {
  43  
  44          // clientName must be a non-zero length alphanumeric string
  45          if (preg_match('/\W/', $clientName)) {
  46              throw new InvalidArgumentException(
  47                  'Only alphanumeric characters allowed in client name.');
  48          }
  49  
  50          if (strlen($clientName) == 0) {
  51              throw new InvalidArgumentException(
  52                  'Client name must not be a zero length string.');
  53          }
  54  
  55          $this->clientName = $clientName;
  56          $this->allow('client', 'incoming',
  57              array('clientName' => $clientName));
  58      }
  59  
  60      /**
  61       * Allow the user of this token to make outgoing connections.
  62       *
  63       * @param $appSid the application to which this token grants access
  64       * @param $appParams signed parameters that the user of this token cannot
  65       *        overwrite.
  66       */
  67      public function allowClientOutgoing($appSid, array $appParams=array())
  68      {
  69          $this->allow('client', 'outgoing', array(
  70              'appSid' => $appSid,
  71              'appParams' => http_build_query($appParams, '', '&')));
  72      }
  73  
  74      /**
  75       * Allow the user of this token to access their event stream.
  76       *
  77       * @param $filters key/value filters to apply to the event stream
  78       */
  79      public function allowEventStream(array $filters=array())
  80      {
  81          $this->allow('stream', 'subscribe', array(
  82              'path' => '/2010-04-01/Events',
  83              'params' => http_build_query($filters, '', '&'),
  84          ));
  85      }
  86  
  87      /**
  88       * Generates a new token based on the credentials and permissions that
  89       * previously has been granted to this token.
  90       *
  91       * @param $ttl the expiration time of the token (in seconds). Default
  92       *        value is 3600 (1hr)
  93       * @return the newly generated token that is valid for $ttl seconds
  94       */
  95      public function generateToken($ttl = 3600)
  96      {
  97          $payload = array(
  98              'scope' => array(),
  99              'iss' => $this->accountSid,
 100              'exp' => time() + $ttl,
 101          );
 102          $scopeStrings = array();
 103  
 104          foreach ($this->scopes as $scope) {
 105              if ($scope->privilege == "outgoing" && $this->clientName)
 106                  $scope->params["clientName"] = $this->clientName;
 107              $scopeStrings[] = $scope->toString();
 108          }
 109  
 110          $payload['scope'] = implode(' ', $scopeStrings);
 111          return JWT::encode($payload, $this->authToken, 'HS256');
 112      }
 113  
 114      protected function allow($service, $privilege, $params) {
 115          $this->scopes[] = new ScopeURI($service, $privilege, $params);
 116      }
 117  }
 118  
 119  /**
 120   * Scope URI implementation
 121   *
 122   * Simple way to represent configurable privileges in an OAuth
 123   * friendly way. For our case, they look like this:
 124   *
 125   * scope:<service>:<privilege>?<params>
 126   *
 127   * For example:
 128   * scope:client:incoming?name=jonas
 129   *
 130   * @author Jeff Lindsay <[email protected]>
 131   */
 132  class ScopeURI
 133  {
 134      public $service;
 135      public $privilege;
 136      public $params;
 137  
 138      public function __construct($service, $privilege, $params = array())
 139      {
 140          $this->service = $service;
 141          $this->privilege = $privilege;
 142          $this->params = $params;
 143      }
 144  
 145      public function toString()
 146      {
 147          $uri = "scope:{$this->service}:{$this->privilege}";
 148          if (count($this->params)) {
 149              $uri .= "?".http_build_query($this->params, '', '&');
 150          }
 151          return $uri;
 152      }
 153  
 154      /**
 155       * Parse a scope URI into a ScopeURI object
 156       *
 157       * @param string    $uri  The scope URI
 158       * @return ScopeURI The parsed scope uri
 159       */
 160      public static function parse($uri)
 161      {
 162          if (strpos($uri, 'scope:') !== 0) {
 163              throw new UnexpectedValueException(
 164                  'Not a scope URI according to scheme');
 165          }
 166  
 167          $parts = explode('?', $uri, 1);
 168          $params = null;
 169  
 170          if (count($parts) > 1) {
 171              parse_str($parts[1], $params);
 172          }
 173  
 174          $parts = explode(':', $parts[0], 2);
 175  
 176          if (count($parts) != 3) {
 177              throw new UnexpectedValueException(
 178                  'Not enough parts for scope URI');
 179          }
 180  
 181          list($scheme, $service, $privilege) = $parts;
 182          return new ScopeURI($service, $privilege, $params);
 183      }
 184  
 185  }
 186  
 187  /**
 188   * JSON Web Token implementation
 189   *
 190   * Minimum implementation used by Realtime auth, based on this spec:
 191   * http://self-issued.info/docs/draft-jones-json-web-token-01.html.
 192   *
 193   * @author Neuman Vong <[email protected]>
 194   */
 195  class JWT
 196  {
 197      /**
 198       * @param string      $jwt    The JWT
 199       * @param string|null $key    The secret key
 200       * @param bool        $verify Don't skip verification process
 201       *
 202       * @return object The JWT's payload as a PHP object
 203       */
 204      public static function decode($jwt, $key = null, $verify = true)
 205      {
 206          $tks = explode('.', $jwt);
 207          if (count($tks) != 3) {
 208              throw new UnexpectedValueException('Wrong number of segments');
 209          }
 210          list($headb64, $payloadb64, $cryptob64) = $tks;
 211          if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))
 212          ) {
 213              throw new UnexpectedValueException('Invalid segment encoding');
 214          }
 215          if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($payloadb64))
 216          ) {
 217              throw new UnexpectedValueException('Invalid segment encoding');
 218          }
 219          $sig = JWT::urlsafeB64Decode($cryptob64);
 220          if ($verify) {
 221              if (empty($header->alg)) {
 222                  throw new DomainException('Empty algorithm');
 223              }
 224              if ($sig != JWT::sign("$headb64.$payloadb64", $key, $header->alg)) {
 225                  throw new UnexpectedValueException('Signature verification failed');
 226              }
 227          }
 228          return $payload;
 229      }
 230  
 231      /**
 232        * @param object|array $payload PHP object or array
 233        * @param string       $key     The secret key
 234        * @param string       $algo    The signing algorithm
 235        *
 236        * @return string A JWT
 237        */
 238      public static function encode($payload, $key, $algo = 'HS256')
 239      {
 240          $header = array('typ' => 'JWT', 'alg' => $algo);
 241  
 242          $segments = array();
 243          $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
 244          $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
 245          $signing_input = implode('.', $segments);
 246  
 247          $signature = JWT::sign($signing_input, $key, $algo);
 248          $segments[] = JWT::urlsafeB64Encode($signature);
 249  
 250          return implode('.', $segments);
 251      }
 252  
 253      /**
 254       * @param string $msg    The message to sign
 255       * @param string $key    The secret key
 256       * @param string $method The signing algorithm
 257       *
 258       * @return string An encrypted message
 259       */
 260      public static function sign($msg, $key, $method = 'HS256')
 261      {
 262          $methods = array(
 263              'HS256' => 'sha256',
 264              'HS384' => 'sha384',
 265              'HS512' => 'sha512',
 266          );
 267          if (empty($methods[$method])) {
 268              throw new DomainException('Algorithm not supported');
 269          }
 270          return hash_hmac($methods[$method], $msg, $key, true);
 271      }
 272  
 273      /**
 274       * @param string $input JSON string
 275       *
 276       * @return object Object representation of JSON string
 277       */
 278      public static function jsonDecode($input)
 279      {
 280          $obj = json_decode($input);
 281          if (function_exists('json_last_error') && $errno = json_last_error()) {
 282              JWT::handleJsonError($errno);
 283          }
 284          else if ($obj === null && $input !== 'null') {
 285              throw new DomainException('Null result with non-null input');
 286          }
 287          return $obj;
 288      }
 289  
 290      /**
 291       * @param object|array $input A PHP object or array
 292       *
 293       * @return string JSON representation of the PHP object or array
 294       */
 295      public static function jsonEncode($input)
 296      {
 297          $json = json_encode($input);
 298          if (function_exists('json_last_error') && $errno = json_last_error()) {
 299              JWT::handleJsonError($errno);
 300          }
 301          else if ($json === 'null' && $input !== null) {
 302              throw new DomainException('Null result with non-null input');
 303          }
 304          return $json;
 305      }
 306  
 307      /**
 308       * @param string $input A base64 encoded string
 309       *
 310       * @return string A decoded string
 311       */
 312      public static function urlsafeB64Decode($input)
 313      {
 314          $padlen = 4 - strlen($input) % 4;
 315          $input .= str_repeat('=', $padlen);
 316          return base64_decode(strtr($input, '-_', '+/'));
 317      }
 318  
 319      /**
 320       * @param string $input Anything really
 321       *
 322       * @return string The base64 encode of what you passed in
 323       */
 324      public static function urlsafeB64Encode($input)
 325      {
 326          return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
 327      }
 328  
 329      /**
 330       * @param int $errno An error number from json_last_error()
 331       *
 332       * @return void
 333       */
 334      private static function handleJsonError($errno)
 335      {
 336          $messages = array(
 337              JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
 338              JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
 339              JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
 340          );
 341          throw new DomainException(isset($messages[$errno])
 342              ? $messages[$errno]
 343              : 'Unknown JSON error: ' . $errno
 344          );
 345      }
 346  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1