HPCloud-PHP  1.2.0
PHP bindings for HPCloud and OpenStack services.
 All Classes Namespaces Files Functions Variables Pages
IdentityServices.php
Go to the documentation of this file.
1 <?php
2 /* ============================================================================
3 (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
8 the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 ============================================================================ */
22 /**
23  * @file
24  *
25  * This file contains the main IdentityServices class.
26  */
27 
28 namespace HPCloud\Services;
29 
30 /**
31  * IdentityServices provides authentication and authorization.
32  *
33  * IdentityServices (a.k.a. Keystone) provides a central service for managing
34  * other services. Through it, you can do the following:
35  *
36  * - Authenticate
37  * - Obtain tokens valid accross services
38  * - Obtain a list of the services currently available with a token
39  * - Associate with tenants using tenant IDs.
40  *
41  * @b AUTHENTICATION
42  *
43  * The authentication process consists of a single transaction during which the
44  * client (us) submits credentials and the server verifies those credentials,
45  * returning a token (for subsequent requests), account information, and the
46  * service catalog.
47  *
48  * Authentication credentials:
49  *
50  * - Username and password
51  * - Account ID and Secret Key
52  *
53  * Other mechanisms may be supported in the future.
54  *
55  * @b TENANTS
56  *
57  * Services are associated with tenants. A token is returned when
58  * authentication succeeds. It *may* be associated with a tenant. If it is not,
59  * it is called "unscoped", and it will not have access to any services.
60  *
61  * A token that is associated with a tenant is considered "scoped". This token
62  * can be used to access any of the services attached to that tenant.
63  *
64  * There are two different ways to attach a tenant to a token:
65  *
66  * - During authentication, provide a tenant ID. This will attach a tenant at
67  * the outset.
68  * - After authentication, "rescope" the token to attach it to a tenant. This
69  * is done with the rescope() method.
70  *
71  * <b>Where do I get a tenant ID?</b>
72  *
73  * There are two notable places to get this information:
74  *
75  * A list of tenants associated with this account can be obtain programatically
76  * using the tenants() method on this object.
77  *
78  * HPCloud customers can find their tenant ID in the console along with their
79  * account ID and secret key.
80  *
81  * @b EXAMPLE
82  *
83  * The following example illustrates typical use of this class.
84  *
85  * @code
86  * <?php
87  * // You may need to use \HPCloud\Bootstrap to set things up first.
88  *
89  * use \HPCloud\Services\IdentityServices;
90  *
91  * // Create a new object with the endpoint URL (no version number)
92  * $ident = new IdentityServices('https://example.com:35357');
93  *
94  * // Authenticate and set the tenant ID simultaneously.
95  * $ident->authenticateAsUser('butcher@hp.com', 'password', '1234567');
96  *
97  * // The token to use when connecting to other services:
98  * $token = $ident->token();
99  *
100  * // The tenant ID.
101  * $tenant = $ident->tenantId();
102  *
103  * // Details about what services this token can access.
104  * $services = $ident->serviceCatalog();
105  *
106  * // List all available tenants.
107  * $tenants = $ident->tenants();
108  *
109  * // Switch to a different tenant.
110  * $ident->rescope($tenants[0]['id']);
111  *
112  * ?>
113  * @endcode
114  *
115  * <b>PERFORMANCE CONSIDERATIONS</b>
116  *
117  * The following methods require network requests:
118  *
119  * - authenticate()
120  * - authenticateAsUser()
121  * - authenticateAsAccount()
122  * - tenants()
123  * - rescope()
124  *
125  * <b>Serializing</b>
126  *
127  * IdentityServices has been intentionally built to serialize well.
128  * This allows implementors to cache IdentityServices objects rather
129  * than make repeated requests for identity information.
130  *
131  */
132 class IdentityServices /*implements Serializable*/ {
133  /**
134  * The version of the API currently supported.
135  */
136  const API_VERSION = '2.0';
137  /**
138  * The full OpenStack accept type.
139  */
140  const ACCEPT_TYPE = 'application/json';
141  // This is no longer supported.
142  //const ACCEPT_TYPE = 'application/vnd.openstack.identity+json;version=2.0';
143 
144  /**
145  * The URL to the CS endpoint.
146  */
147  protected $endpoint;
148 
149  /**
150  * The details sent with the token.
151  *
152  * The exact details of this array will differ depending on what type of
153  * authentication is used. For example, authenticating by username and
154  * password will set tenant information. Authenticating by account ID and
155  * secret, however, will leave the tenant section empty.
156  *
157  * This is an associative array looking like this:
158  *
159  * @code
160  * <?php
161  * array(
162  * 'id' => 'auth_123abc321defef99',
163  * // Only non-empty for username/password auth.
164  * 'tenant' => array(
165  * 'id' => '123456',
166  * 'name' => 'matt.butcher@hp.com',
167  * ),
168  * 'expires' => '2012-01-24T12:46:01.682Z'
169  * );
170  * @endcode
171  */
172  protected $tokenDetails;
173 
174  /**
175  * The service catalog.
176  */
177  protected $catalog = array();
178 
179  protected $userDetails;
180 
181  /**
182  * Build a new IdentityServices object.
183  *
184  * Each object is bound to a particular identity services endpoint.
185  *
186  * For the URL, you are advised to use the version <i>without</i> a
187  * version number at the end, e.g. http://cs.example.com/ rather
188  * than http://cs.example.com/v2.0. The version number must be
189  * controlled by the library.
190  *
191  * @attention
192  * If a version is included in the URI, the library will attempt to use
193  * that URI.
194  *
195  * @code
196  * <?php
197  * $cs = new \HPCloud\Services\IdentityServices('http://example.com');
198  * $token = $cs->authenticateAsAccount($accountId, $accessKey);
199  * ?>
200  * @endcode
201  *
202  * @param string $url
203  * An URL pointing to the Identity Services endpoint. Note that you do
204  * not need the version identifier in the URL, as version information
205  * is sent in the HTTP headers rather than in the URL. <b>The URL
206  * should <i>always</i> be to an SSL/TLS encrypted endpoint.</b>.
207  */
208  public function __construct($url) {
209  $parts = parse_url($url);
210 
211  if (!empty($parts['path'])) {
212  $this->endpoint = rtrim($url, '/');
213  }
214  else {
215  $this->endpoint = rtrim($url, '/') . '/v' . self::API_VERSION;
216  }
217  }
218 
219  /**
220  * Get the endpoint URL.
221  *
222  * This includes version number, so in that regard it is not an identical
223  * URL to the one passed into the constructor.
224  *
225  * @retval string
226  * @return string
227  * The complete URL to the identity services endpoint.
228  */
229  public function url() {
230  return $this->endpoint;
231  }
232 
233  /**
234  * Send an authentication request.
235  *
236  * @remark EXPERT: This allows authentication requests at a low level. For simple
237  * authentication requests using account number or username, see the
238  * authenticateAsUser() and authenticateAsAccount() methods.
239  *
240  * Here is an example of username/password-based authentication done with
241  * the authenticate() method:
242  * @code
243  * <?php
244  * $cs = new \HPCloud\Services\IdentityServices($url);
245  * $ops = array(
246  * 'passwordCredentials' => array(
247  * 'username' => $username,
248  * 'password' => $password,
249  * ),
250  * 'tenantId' => $tenantId,
251  * );
252  * $token = $cs->authenticate($ops);
253  * ?>
254  * @endcode
255  *
256  * Note that the same authentication can be done by authenticateAsUser().
257  *
258  * @param array $ops
259  * An associative array of authentication operations and their respective
260  * parameters.
261  * @retval string
262  * @return string
263  * The token. This is returned for simplicity. The full response is used
264  * to populate this object's service catalog, etc. The token is also
265  * retrievable with token().
266  * @throws HPCloud::Transport::AuthorizationException
267  * If authentication failed.
268  * @throws HPCloud::Exception
269  * For abnormal network conditions. The message will give an indication as
270  * to the underlying problem.
271  */
272  public function authenticate(array $ops) {
273  $url = $this->url() . '/tokens';
274  $envelope = array(
275  'auth' => $ops,
276  );
277 
278  $body = json_encode($envelope);
279 
280  $headers = array(
281  'Content-Type' => 'application/json',
282  'Accept' => self::ACCEPT_TYPE,
283  'Content-Length' => strlen($body),
284  );
285 
286  //print $body . PHP_EOL;
287 
288  $client = \HPCloud\Transport::instance();
289 
290  $response = $client->doRequest($url, 'POST', $headers, $body);
291 
292  $this->handleResponse($response);
293 
294 
295  return $this->token();
296  }
297 
298  /**
299  * Authenticate to Identity Services with username, password, and either
300  * tenant ID or tenant Name.
301  *
302  * Given an HPCloud username and password, authenticate to Identity Services.
303  * Identity Services will then issue a token that can be used to access other
304  * HPCloud services.
305  *
306  * If a tenant ID is provided, this will also associate the user with the
307  * given tenant ID. If a tenant Name is provided, this will associate the user
308  * with the given tenant Name. Only the tenant ID or tenant Name needs to be
309  * given, not both.
310  *
311  * If no tenant ID or tenant Name is given, it will likely be necessary to
312  * rescope() the request (See also tenants()).
313  *
314  * Other authentication methods:
315  *
316  * - authenticateAsAccount()
317  * - authenticate()
318  *
319  * @param string $username
320  * A valid username.
321  * @param string $password
322  * A password string.
323  * @param string $tenantId
324  * The tenant ID for this account. This can be obtained through the
325  * HPCloud console.
326  * @param string $tenantName
327  * The tenant Name for this account. This can be obtained through the
328  * HPCloud console.
329  * @throws HPCloud::Transport::AuthorizationException
330  * If authentication failed.
331  * @throws HPCloud::Exception
332  * For abnormal network conditions. The message will give an indication as
333  * to the underlying problem.
334  */
335  public function authenticateAsUser($username, $password, $tenantId = NULL, $tenantName = NULL) {
336  $ops = array(
337  'passwordCredentials' => array(
338  'username' => $username,
339  'password' => $password,
340  ),
341  );
342 
343  // If a tenant ID is provided, added it to the auth array.
344  if (!empty($tenantId)) {
345  $ops['tenantId'] = $tenantId;
346  }
347  elseif (!empty($tenantName)) {
348  $ops['tenantName'] = $tenantName;
349  }
350 
351 
352  return $this->authenticate($ops);
353  }
354  /**
355  * Authenticate to HPCloud using your account ID and access key.
356  *
357  * Given an account ID and and access key (secret key), authenticate
358  * to Identity Services. Identity Services will then issue a token that can be
359  * used with other HPCloud services, such as Object Storage (aka Swift).
360  *
361  * The account ID and access key information can be found in the account
362  * section of the console.
363  *
364  * The third and fourth paramaters allow you to specify a tenant ID or
365  * tenantName. In order to access services, this object will need a tenant ID
366  * or tenant name. If none is specified, it can be set later using rescope().
367  * The tenants() method can be used to get a list of all available tenant IDs
368  * for this token.
369  *
370  * Other authentication methods:
371  *
372  * - authenticateAsUser()
373  * - authenticate()
374  *
375  * @param string $account
376  * The account ID. It should look something like this:
377  * 1234567890:abcdef123456.
378  * @param string $key
379  * The access key (i.e. secret key), which should be a series of
380  * ASCII letters and digits.
381  * @param string $tenantId
382  * A valid tenant ID. This will be used to associate a tenant's services
383  * with this token.
384  * @param string $tenantName
385  * The tenant Name for this account. This can be obtained through the
386  * HPCloud console.
387  * @retval string
388  * @return string
389  * The auth token.
390  * @throws HPCloud::Transport::AuthorizationException
391  * If authentication failed.
392  * @throws HPCloud::Exception
393  * For abnormal network conditions. The message will give an indication as
394  * to the underlying problem.
395  */
396  public function authenticateAsAccount($account, $key, $tenantId = NULL, $tenantName = NULL) {
397  $ops = array(
398  'apiAccessKeyCredentials' => array(
399  'accessKey' => $account,
400  'secretKey' => $key,
401  ),
402  );
403 
404  if (!empty($tenantId)) {
405  $ops['tenantId'] = $tenantId;
406  }
407  elseif (!empty($tenantName)) {
408  $ops['tenantName'] = $tenantName;
409  }
410 
411  return $this->authenticate($ops);
412  }
413 
414 
415  /**
416  * Get the token.
417  *
418  * This will not be populated until after one of the authentication
419  * methods has been run.
420  *
421  * @retval string
422  * @return string
423  * The token ID to be used in subsequent calls.
424  */
425  public function token() {
426  return $this->tokenDetails['id'];
427  }
428 
429  /**
430  * Get the tenant ID associated with this token.
431  *
432  * If this token has a tenant ID, the ID will be returned. Otherwise, this
433  * will return NULL.
434  *
435  * This will not be populated until after an authentication method has been
436  * run.
437  *
438  * @retval string
439  * @return string
440  * The tenant ID if available, or NULL.
441  */
442  public function tenantId() {
443  if (!empty($this->tokenDetails['tenant']['id'])) {
444  return $this->tokenDetails['tenant']['id'];
445  }
446  }
447 
448  /**
449  * Get the tenant name associated with this token.
450  *
451  * If this token has a tenant name, the name will be returned. Otherwise, this
452  * will return NULL.
453  *
454  * This will not be populated until after an authentication method has been
455  * run.
456  *
457  * @retval string
458  * @return string
459  * The tenant name if available, or NULL.
460  */
461  public function tenantName() {
462  if (!empty($this->tokenDetails['tenant']['name'])) {
463  return $this->tokenDetails['tenant']['name'];
464  }
465  }
466 
467  /**
468  * Get the token details.
469  *
470  * This returns an associative array with several pieces of information
471  * about the token, including:
472  *
473  * - id: The token itself
474  * - expires: When the token expires
475  * - tenant_id: The tenant ID of the authenticated user.
476  * - tenant_name: The username of the authenticated user.
477  *
478  * @code
479  * <?php
480  * array(
481  * 'id' => 'auth_123abc321defef99',
482  * 'tenant' => array(
483  * 'id' => '123456',
484  * 'name' => 'matt.butcher@hp.com',
485  * ),
486  * 'expires' => '2012-01-24T12:46:01.682Z'
487  * );
488  * @endcode
489  *
490  * This will not be populated until after authentication has been done.
491  *
492  * @retval array
493  * @return array
494  * An associative array of details.
495  */
496  public function tokenDetails() {
497  return $this->tokenDetails;
498  }
499 
500  /**
501  * Check whether the current identity has an expired token.
502  *
503  * This does not perform a round-trip to the server. Instead, it compares the
504  * machine's local timestamp with the server's expiration time stamp. A
505  * mis-configured machine timestamp could give spurious results.
506  *
507  * @retval boolean
508  * @return boolean
509  * This will return FALSE if there is a current token and it has
510  * not yet expired (according to the date info). In all other cases
511  * it returns TRUE.
512  */
513  public function isExpired() {
514  $details = $this->tokenDetails();
515 
516  if (empty($details['expires'])) {
517  return TRUE;
518  }
519 
520  $currentDateTime = new \DateTime('now');
521  $expireDateTime = new \DateTime($details['expires']);
522 
523  return $currentDateTime > $expireDateTime;
524  }
525 
526  /**
527  * Get the service catalog, optionaly filtering by type.
528  *
529  * This returns the service catalog (largely unprocessed) that
530  * is returned during an authentication request. If a type is passed in,
531  * only entries of that type are returned. If no type is passed in, the
532  * entire service catalog is returned.
533  *
534  * The service catalog contains information about what services (if any) are
535  * available for the present user. Object storage (Swift) Compute instances
536  * (Nova) and other services will each be listed here if they are enabled
537  * on your account. Only services that have been turned on for the account
538  * will be available. (That is, even if you *can* create a compute instance,
539  * until you have actually created one, it will not show up in this list.)
540  *
541  * One of the authentication methods MUST be run before obtaining the service
542  * catalog.
543  *
544  * The return value is an indexed array of associative arrays, where each assoc
545  * array describes an individual service.
546  * @code
547  * <?php
548  * array(
549  * array(
550  * 'name' : 'Object Storage',
551  * 'type' => 'object-store',
552  * 'endpoints' => array(
553  * 'tenantId' => '123456',
554  * 'adminURL' => 'https://example.hpcloud.net/1.0',
555  * 'publicURL' => 'https://example.hpcloud.net/1.0/123456',
556  * 'region' => 'region-a.geo-1',
557  * 'id' => '1.0',
558  * ),
559  * ),
560  * array(
561  * 'name' => 'Identity',
562  * 'type' => 'identity'
563  * 'endpoints' => array(
564  * 'publicURL' => 'https://example.hpcloud.net/1.0/123456',
565  * 'region' => 'region-a.geo-1',
566  * 'id' => '2.0',
567  * 'list' => 'http://example.hpcloud.net/extension',
568  * ),
569  * )
570  *
571  * );
572  * ?>
573  * @endcode
574  *
575  * This will not be populated until after authentication has been done.
576  *
577  * Types:
578  *
579  * While this is by no means an exhaustive list, here are a few types that
580  * might appear in a service catalog (and upon which you can filter):
581  *
582  * - identity: Identity Services (i.e. Keystone)
583  * - compute: Compute instance (Nova)
584  * - object-store: Object Storage (Swift)
585  * - hpext:cdn: HPCloud CDN service (yes, the colon belongs in there)
586  *
587  * Other services will be added.
588  *
589  * @todo Paging on the service catalog is not yet implemented.
590  *
591  * @retval array
592  * @return array
593  * An associative array representing
594  * the service catalog.
595  */
596  public function serviceCatalog($type = NULL) {
597  // If no type is specified, return the entire
598  // catalog.
599  if (empty($type)) {
600  return $this->serviceCatalog;
601  }
602 
603  $list = array();
604  foreach ($this->serviceCatalog as $entry) {
605  if ($entry['type'] == $type) {
606  $list[] = $entry;
607  }
608  }
609 
610  return $list;
611  }
612 
613  /**
614  * Get information about the currently authenticated user.
615  *
616  * This returns an associative array of information about the authenticated
617  * user, including the user's username and roles.
618  *
619  * The returned data is structured like this:
620  * @code
621  * <?php
622  * array(
623  * 'name' => 'matthew.butcher@hp.com',
624  * 'id' => '1234567890'
625  * 'roles' => array(
626  * array(
627  * 'name' => 'domainuser',
628  * 'serviceId' => '100',
629  * 'id' => '000100400010011',
630  * ),
631  * // One array for each role...
632  * ),
633  * )
634  * ?>
635  * @endcode
636  *
637  * This will not have data until after authentication has been done.
638  *
639  * @retval array
640  * @return array
641  * An associative array, as described above.
642  */
643  public function user() {
644  return $this->userDetails;
645  }
646 
647  /**
648  * Get a list of all tenants associated with this account.
649  *
650  * If a valid token is passed into this object, the method can be invoked
651  * before authentication. However, if no token is supplied, this attempts
652  * to use the one returned by an authentication call.
653  *
654  * Returned data will follow this format:
655  *
656  * @code
657  * <?php
658  * array(
659  * array(
660  * "id" => "395I91234514446",
661  * "name" => "Banking Tenant Services",
662  * "description" => "Banking Tenant Services for TimeWarner",
663  * "enabled" => TRUE,
664  * "created" => "2011-11-29T16:59:52.635Z",
665  * "updated" => "2011-11-29T16:59:52.635Z",
666  * ),
667  * );
668  * ?>
669  * @endcode
670  *
671  * Note that this method invokes a new request against the remote server.
672  *
673  * @retval array
674  * @return array
675  * An indexed array of tenant info. Each entry will be an associative
676  * array containing tenant details.
677  * @throws HPCloud::Transport::AuthorizationException
678  * If authentication failed.
679  * @throws HPCloud::Exception
680  * For abnormal network conditions. The message will give an indication as
681  * to the underlying problem.
682  */
683  public function tenants($token = NULL) {
684  $url = $this->url() . '/tenants';
685 
686  if (empty($token)) {
687  $token = $this->token();
688  }
689 
690  $headers = array(
691  'X-Auth-Token' => $token,
692  'Accept' => 'application/json',
693  //'Content-Type' => 'application/json',
694  );
695 
696  $client = \HPCloud\Transport::instance();
697  $response = $client->doRequest($url, 'GET', $headers);
698 
699  $raw = $response->content();
700  $json = json_decode($raw, TRUE);
701 
702  return $json['tenants'];
703 
704  }
705 
706  /**
707  * @see HPCloud::Services::IdentityServices::rescopeUsingTenantId()
708  * @deprecated
709  */
710  public function rescope($tenantId) {
711  return $this->rescopeUsingTenantId($tenantId);
712  }
713 
714  /**
715  * Rescope the authentication token to a different tenant.
716  *
717  * Note that this will rebuild the service catalog and user information for
718  * the current object, since this information is sensitive to tenant info.
719  *
720  * An authentication token can be in one of two states:
721  *
722  * - unscoped: It has no associated tenant ID.
723  * - scoped: It has a tenant ID, and can thus access that tenant's services.
724  *
725  * This method allows you to do any of the following:
726  *
727  * - Begin with an unscoped token, and assign it a tenant ID.
728  * - Change a token from one tenant ID to another (re-scoping).
729  * - Remove the tenant ID from a scoped token (unscoping).
730  *
731  * @param string $tenantId
732  * The tenant ID that this present token should be bound to. If this is the
733  * empty string (`''`), the present token will be "unscoped" and its tenant
734  * ID will be removed.
735  *
736  * @retval string
737  * @return string
738  * The authentication token.
739  * @throws HPCloud::Transport::AuthorizationException
740  * If authentication failed.
741  * @throws HPCloud::Exception
742  * For abnormal network conditions. The message will give an indication as
743  * to the underlying problem.
744  */
745  public function rescopeUsingTenantId($tenantId) {
746  $url = $this->url() . '/tokens';
747  $token = $this->token();
748  $data = array(
749  'auth' => array(
750  'tenantId' => $tenantId,
751  'token' => array(
752  'id' => $token,
753  ),
754  ),
755  );
756  $body = json_encode($data);
757 
758  $headers = array(
759  'Accept' => self::ACCEPT_TYPE,
760  'Content-Type' => 'application/json',
761  'Content-Length' => strlen($body),
762  //'X-Auth-Token' => $token,
763  );
764 
765  $client = \HPCloud\Transport::instance();
766  $response = $client->doRequest($url, 'POST', $headers, $body);
767  $this->handleResponse($response);
768 
769  return $this->token();
770  }
771 
772  /**
773  * Rescope the authentication token to a different tenant.
774  *
775  * Note that this will rebuild the service catalog and user information for
776  * the current object, since this information is sensitive to tenant info.
777  *
778  * An authentication token can be in one of two states:
779  *
780  * - unscoped: It has no associated tenant ID.
781  * - scoped: It has a tenant ID, and can thus access that tenant's services.
782  *
783  * This method allows you to do any of the following:
784  *
785  * - Begin with an unscoped token, and assign it a tenant ID.
786  * - Change a token from one tenant ID to another (re-scoping).
787  * - Remove the tenant ID from a scoped token (unscoping).
788  *
789  * @param string $tenantName
790  * The tenant name that this present token should be bound to. If this is the
791  * empty string (`''`), the present token will be "unscoped" and its tenant
792  * name will be removed.
793  *
794  * @retval string
795  * @return string
796  * The authentication token.
797  * @throws HPCloud::Transport::AuthorizationException
798  * If authentication failed.
799  * @throws HPCloud::Exception
800  * For abnormal network conditions. The message will give an indication as
801  * to the underlying problem.
802  */
803  public function rescopeUsingTenantName($tenantName) {
804  $url = $this->url() . '/tokens';
805  $token = $this->token();
806  $data = array(
807  'auth' => array(
808  'tenantName' => $tenantName,
809  'token' => array(
810  'id' => $token,
811  ),
812  ),
813  );
814  $body = json_encode($data);
815 
816  $headers = array(
817  'Accept' => self::ACCEPT_TYPE,
818  'Content-Type' => 'application/json',
819  'Content-Length' => strlen($body),
820  //'X-Auth-Token' => $token,
821  );
822 
823  $client = \HPCloud\Transport::instance();
824  $response = $client->doRequest($url, 'POST', $headers, $body);
825  $this->handleResponse($response);
826 
827  return $this->token();
828  }
829 
830  /**
831  * Given a response object, populate this object.
832  *
833  * This parses the JSON data and parcels out the data to the appropriate
834  * fields.
835  *
836  * @param object $response HPCloud::Transport::Response
837  * A response object.
838  *
839  * @retval HPCloud::Services::IdentityServices
840  * @return \HPCloud\Services\IdentityServices
841  * $this for the current object so it can be used in chaining.
842  */
843  protected function handleResponse($response) {
844  $json = json_decode($response->content(), TRUE);
845  // print_r($json);
846 
847  $this->tokenDetails = $json['access']['token'];
848  $this->userDetails = $json['access']['user'];
849  $this->serviceCatalog = $json['access']['serviceCatalog'];
850 
851  return $this;
852  }
853 
854  /* Not necessary.
855  public function serialize() {
856  $data = array(
857  'tokenDetails' => $this->tokenDetails,
858  'userDetails' => $this->userDetails,
859  'serviceCatalog' => $this->serviceCatalog,
860  'endpoint' => $this->endpoint,
861  );
862  return serialize($data);
863  }
864 
865  public function unserialize($data) {
866  $vals = unserialize($data);
867  $this->tokenDetails = $vals['tokenDetails'];
868  $this->userDetails = $vals['userDetails'];
869  $this->serviceCatalog = $vals['serviceCatalog'];
870  $this->endpoint = $vals['endpoint'];
871  }
872  */
873 
874 }