GithubHelp home page GithubHelp logo

josegorchs / stormpath-sdk-php Goto Github PK

View Code? Open in Web Editor NEW

This project forked from stormpath/stormpath-sdk-php

0.0 2.0 0.0 827 KB

PHP SDK for the Stormpath User Management and Authentication REST+JSON API

PHP 100.00%

stormpath-sdk-php's Introduction

Build Status Codecov Total Downloads Latest Stable Version License

Stormpath PHP SDK

Stormpath is the first easy, secure user management and authentication service for developers. This is the PHP SDK to ease integration of its features with any PHP language based application.

Installation

You can install stormpath-sdk-php via Composer.

Via Composer:

stormpath-sdk-php is available on Packagist as the stormpath/sdk package.

On your project root, install Composer

curl -sS https://getcomposer.org/installer | php

Configure the stormpath/sdk dependency in your 'composer.json' file:

"require": {
    "stormpath/sdk": "1.13.*"
}

On your project root, install the the SDK with its dependencies:

php composer.phar install

You're ready to connect with Stormpath!

Provision Your Stormpath Account

If you have not already done so, register as a developer on Stormpath and set up your API credentials and resources:

  1. Create a Stormpath developer account and create your API Keys downloading the apiKey.properties file into a .stormpath folder under your local home directory.

  2. Through the Stormpath Admin UI, create yourself an Application Resource. On the Create New Application screen, make sure the "Create a new directory with this application" box is checked. This will provision a Directory Resource along with your new Application Resource and link the Directory to the Application as an Account Store. This will allow users associated with that Directory Resource to authenticate and have access to that Application Resource.

    It is important to note that although your developer account comes with a built-in Application Resource (called "Stormpath") - you will still need to provision a separate Application Resource.

  3. Take note of the REST URL of the Application you just created. Your web application will communicate with the Stormpath API in the context of this one Application Resource (operations such as: user-creation, authentication, etc.).

Getting Started

  1. Require the Stormpath PHP SDK via the composer auto loader

    require 'vendor/autoload.php';
  2. Configure the client using the API key properties file

    \Stormpath\Client::$apiKeyFileLocation = $_SERVER['HOME'] . '/.stormpath/apiKey.properties';
  3. List all your applications and directories

    $tenant = \Stormpath\Resource\Tenant::get();
    foreach($tenant->applications as $app)
    {
        print $app->name;
    }
    
    foreach($tenant->directories as $dir)
    {
        print $dir->name;
    }
  4. Get access to the specific application and directory using a specific href.

    $application = \Stormpath\Resource\Application::get($applicationHref);
    
    $directory = \Stormpath\Resource\Directory::get($directoryHref);

    Note:

    The $applicationHref and $directoryHref can be accessed from the Stormpath Administrator Console or retrieved from the code. When you iterate over the object during step 3, you can output the href for the individual objects (eg print $app->href;)

  5. Create an application and auto create a directory as the account store.

    $application = \Stormpath\Resource\Application::create(
      array('name' => 'May Application',
            'description' => 'My Application Description'),
      array('createDirectory' => true)
       );
  6. Create an account for a user on the directory.

    $account = \Stormpath\Resource\Account::instantiate(
      array('givenName' => 'John',
            'surname' => 'Smith',
            'username' => 'johnsmith',
            'email' => '[email protected]',
            'password' => '4P@$$w0rd!'));
    
    $application->createAccount($account);
  7. Update an account

    $account->givenName = 'Johnathan';
    $account->middleName = 'A.';
    $account->save();
  8. Authenticate the Account for use with an application:

    try {
    
        $result = $application->authenticate('johnsmith', '4P@$$w0rd!');
        $account = $result->account;
    
    } catch (\Stormpath\Resource\ResourceError $re)
    {
        print $re->getStatus();
        print $re->getErrorCode();
        print $re->getMessage();
        print $re->getDeveloperMessage();
        print $re->getMoreInfo();
    }
  9. Send a password reset request

    $application->sendPasswordResetEmail('[email protected]');
  10. Create a group in a directory

```php
$group = \Stormpath\Resource\Group::instantiate(array('name' => 'Admins'));

$directory->createGroup($group);
```
  1. Add the account to the group
```php
$group->addAccount($account);
```
  1. Check for account inclusion in group

    $isAdmin = false;
    $search = array('name' => 'Admins');
    
    foreach($account->groups->setSearch($search) as $group)
    {
        // if one group was returned, the account is in
        // the group based on the search criteria
        $isAdmin = true;
    }

Common Uses

Creating a client

All Stormpath features are accessed through a stormpath.Client instance, or a resource created from one. A client needs an API key (made up of an id and a secret) from your Stormpath developer account to manage resources on that account. That API key can be specified in many ways when configuring the Client:

  • The location of API key properties file:

    // This can also be an http location
    $apiKeyFileLocation = '/some/path/to/apiKey.properties';
    \Stormpath\Client::$apiKeyFileLocation = $apiKeyFileLocation;
    
    //Or
    
    $builder = new \Stormpath\ClientBuilder();
    $client = $builder->setApiKeyFileLocation($apiKeyFileLocation)->build();

    You can even identify the names of the properties to use as the API key id and secret. For example, suppose your properties were:

    $foo = 'APIKEYID';
    $bar = 'APIKEYSECRET';

    You could configure the Client with the following parameters:

    \Stormpath\Client::$apiKeyIdPropertyName = $foo;
    \Stormpath\Client::$apiKeySecretPropertyName = $bar;
    
    //Or
    
    $builder = new \Stormpath\ClientBuilder();
    $client = $builder->setApiKeyFileLocation($apiKeyFileLocation)->
                        setApiKeyIdPropertyName($foo)->
                        setApiKeySecretPropertyName($bar)->
                        build();
  • Passing in a valid PHP ini formatted string:

    $apiKeyProperties = "apiKey.id=APIKEYID\napiKey.secret=APIKEYSECRET";
    \Stormpath\Client::$apiKeyProperties = $apiKeyProperties;
    
    //Or
    
    $builder = new \Stormpath\ClientBuilder();
    $client = $builder->setApiKeyProperties($apiKeyProperties)->build();

Note: Only if the client is configured using the static properties, the static calls to resources will run successfully. If the Client is directly instantiated (using the ClientBuilder or the Client constructor), the Client instance must be used to start interactions with Stormpath.

Cache

By default all items will be cached. This will use Array caching if nothing is defined. The caching happens automatically for you so you do not have to think about it. NOTE: Array caching will only store an item in cache within an array. This means an item will only be available within the cache for a single request in the application. Array Caching does not persist across multiple requests. There are many reason why you may want to cache api calls to the Stormpath API where the main reason is speed. Caching allows you to make one api call over a set amount of time while all subsequent calls to the same endpoint will pull data that was cached. By default, the time to live is set to 1 hour, while the time to idle is set to 2 hours.

All of you default options can be overridden by passing an options array during the ClientBuilder. The following is the default array that is provided to the ClientBuilder if no options are overridden.

$cacheManagerOptions = array(
    'cachemanager' => 'Array', //Array, Memcached, Redis, Null, or the full namespaced CacheManager instance
    'memcached' => array(
        array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
    ),
    'redis' => array(
        'host' => '127.0.0.1',
        'port' => 6379,
        'password' => NULL
    ),
    'ttl' => 60, // This value is set in minutes
    'tti' => 120, // This value is set in minutes
    'regions' => array(
      'accounts' => array(
          'ttl' => 60,
          'tti' => 120
       ),
      'applications' => array(
          'ttl' => 60,
          'tti' => 120
       ),
      'directories' => array(
          'ttl' => 60,
          'tti' => 120
       ),
      'groups' => array(
          'ttl' => 60,
          'tti' => 120
       ),
      'tenants' => array(
          'ttl' => 60,
          'tti' => 120
       ),
      
    ) 
);

Only the values you wish to override would need to be supplied in the array that is passed to the ClientBuilder.

The following coule be used to on the Client to set options for the default Memory cacheManager:

 \Stormpath\Client::$cacheManagerOptions = $cacheManagerOptions;

 //Or

 $builder = new \Stormpath\ClientBuilder();
 $client = $builder->setCacheManagerOptions($cacheManagerOptions)->
                     build();

It is just as easy to set a cache manager to override the default Memory.

You could configure the client with the following:

\Stormpath\Client::$cacheManager = 'Memcached';
\Stormpath\Client::$cacheManagerOptions = $cacheManagerOptions;

Doing it this way, the option in the array for the CacheManager will not be used. Setting the CacheManger statically will override the option set in the CacheManagerOptions.

You can also call it without static calls as follows:

$builder = new \Stormpath\ClientBuilder();
$client = $builder->setCacheManager('Memcached')-> //setting this will ignore the 'cachemanager' in options array
                    setCacheManagerOptions($cacheManagerOptions)->
                  build();

In the previous examples, setting the CacheManager either statically or in the 'setCacheManager' method, the key 'cachemanager' in the $cacheManagerOptions array will be ignored.

Disable Cache

Although this is not suggested as it will make more calls and slow your application, you can disable the Cache. This can be accomplished by doing any of the above for setting the cache manager, however you will set it to be the null cache manager. This can be done by setting the manager to Null

Extending Cache

Extending the Cache Manager to supply your own caching is very easy. There are only a couple files that are required. A file that implements Stormpath\Cache\Cache and a file that implements Stormpath\Cache\CacheManager. Take the following if we wanted to create an Array caching system.

  class ArrayCacheManager implements CacheManager {
       public function getCache() { ... }
  }

  class ArrayCache implements Cache {
      public function get($key) { ... }
      public function put($key, $value, $minutes) { ... }
      public function delete($key) { ... }
      public function clear() { ... }
  }

Then you would call it the same way you do for a cache manager normally.

Authentication Scheme Configuration

You can choose one of two authentication schemes to authenticate with Stormpath:

  • Stormpath SAuthc1 Authentication: This is the recommended approach, and the default setting. This approach computes a cryptographic digest of the request and sends the digest value along with the request. If the transmitted digest matches what the Stormpath API server computes for the same request, the request is authenticated. The Stormpath SAuthc1 digest-based authentication scheme is more secure than standard HTTP digest authentication.

  • Basic Authentication: This is only recommended when your application runs in an environment outside of your control, and that environment manipulates your application’s request headers when requests are made. Google App Engine is one known such environment. However, Basic Authentication is not as secure as Stormpath’s SAuthc algorithm, so only use this if you are forced to do so by your application runtime environement.

When no authentication scheme is explicitly configured, Sauthc1 is used by default.

If you must change to basic authentication for these special environments, set the authenticationScheme property using Stormpath::BASIC_AUTHENTICATION_SCHEME or Stormpath::SAUTHC1_AUTHENTICATION_SCHEME:

     \Stormpath\Client::$authenticationScheme = Stormpath::BASIC_AUTHENTICATION_SCHEME;

OR

      $builder = new \Stormpath\ClientBuilder();
      $client = $builder->setAuthenticationScheme(Stormpath::BASIC_AUTHENTICATION_SCHEME)
                     ->build();

Accessing Resources

Most of the work you do with Stormpath is done through the applications and directories you have registered. You use the static getter of resource classes to access them with their REST URL, or via the data store of the client instance:

$application = \Stormpath\Resource\Application::get($applicationHref);

$directory = \Stormpath\Resource\Directory::get($directoryHref);

//Or

$application = $client->
               dataStore->
               getResource($applicationHref, \Stormpath\Stormpath::APPLICATION);

$directory = $client->
             dataStore->
             getResource($directoryHref, \Stormpath\Stormpath::DIRECTORY);

Additional resources are Account, Group, GroupMemberships, AccountStoreMappings, and the single reference to your Tenant.

Creating Resources

Applications, directories and account store mappings can be created directly off their resource classes; or from the tenant resource (or from the application, in the case of account store mapping).

$application = \Stormpath\Resource\Application::create(
  array('name' => 'My App',
        'description' => 'App Description')
  );

$directory = \Stormpath\Resource\Directory::create(
  array('name' => 'My directory',
        'description' => 'My directory description')
  );

$accountStoreMapping = \Stormpath\Resource\AccountStoreMapping::create(
  array('accountStore' => $directory, // this could also be a group
        'application' => $application)
  );

//Or

$application = $client->
               dataStore->
               instantiate(\Stormpath\Stormpath::APPLICATION);
$application->name = 'My App';
$application->description = 'App Description';
$tenant->createApplication($application);

$directory = $client->
             dataStore->
             instantiate(\Stormpath\Stormpath::DIRECTORY);
$directory->name = 'My directory';
$directory->description = 'Directory Description';
$tenant->createDirectory($directory);

$accountStoreMapping = $client->
                       dataStore->
                       instantiate(\Stormpath\Stormpath::ACCOUNT_STORE_MAPPING);
$accountStoreMapping->accountStore = $directory; // this could also be a group
$application->createAccountStoreMapping($accountStoreMapping);

Custom Data

You may find it useful to store your own custom data on resource's. With the Stormpath SDK, we make it easy to do so. All resource's support a Custom Data collection for your own custom use. The CustomData resource is a schema-less JSON object (aka ‘map’, ‘associative array’, or ‘dictionary’) that allows you to specify whatever name/value pairs you wish.

The CustomData resource is always connected to a resource and you can always reach it by calling customData magic method (alias to getCustomData()) on the resource instance:

  $application = \Stormpath\Resource\Application::get($applicationHref);

  $applicationCustomData = $application->customData;

  //Or

  $application = $client->
                 dataStore->
                 getResource($applicationHref, \Stormpath\Stormpath::APPLICATION);
                 
  $applicationCustomData = $application->customData;

In addition to your custom name/value pairs, a CustomData resource will always contain 3 reserved read-only fields:

  • href: The fully qualified location of the custom data resource
  • createdAt: the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string, for example 2017-04-01T14:35:16.235Z
  • modifiedAt: the UTC timestamp with millisecond precision of when the resource was last updated in Stormpath as an ISO 8601 formatted string.

You can store an unlimited number of additional name/value pairs in the CustomData resource, with the following restrictions:

  • The total storage size of a single CustomData resource cannot exceed 10 MB (megabytes). The href, createdAt and modifiedAt field names and values do not count against your resource size quota.
  • Field names must:
    • be 1 or more characters long, but less than or equal to 255 characters long (1 <= N <= 255).
    • contain only alphanumeric characters 0-9A-Za-z, underscores _ or dashes - but cannot start with a dash -.
    • may not equal any of the following reserved names: href, createdAt, modifiedAt, meta, spMeta, spmeta, ionmeta, or ionMeta.

Create Custom Data

An example of creating an account with custom data

  $account = $client->dataStore->instantiate(\Stormpath\Stormpath::ACCOUNT);
  $account->email = '[email protected]';
  $account->givenName = 'John';
  $account->password ='4P@$$w0rd!';
  $account->surname = 'Smith';
  $account->username = 'johnsmith';
  
  $customData = $account->customData;
  $customData->rank = "Captain";
  $customData->birthDate = "2305-07-13";
  $customData->favoriteDrink = "favoriteDrink";
  
  $directory->createAccount($account);

Retrieve Custom Data

An example of retrieving custom data for an application.

  $application = $client->
                     dataStore->
                     getResource($applicationHref, \Stormpath\Stormpath::APPLICATION);
                     
  $applicationCustomData = $application->customData;

After you have access to the whole custom data resource, you can then retrieve a specific property with the following

  $property = $applicationCustomData->property;

Update Custom Data

  $customData->favoriteColor = "red";
  $customData->hobby = "Kendo";
  $customData->save();

Delete Custom Data

You may delete all of a resource's custom data by invoking the delete() method to the resource's CustomData

   ${RESOURCE}->customData->delete();

This will delete all of the respective resource's custom data fields, but it leaves the CustomData placeholder in the resource. You cannot delete the CustomData resource entirely – it will be automatically permanently deleted when the resource is deleted.

Delete Custom Data Field

You may also delete an individual custom data field entirely by calling the remove() method on the resource's CustomData while stating the custom data field as a parameter.

  $customData->remove("favoriteColor");

ID Site

ID Site allows you to easily add authentication to your application. It is also very easy to use.
To use ID Site, You need to use the SDK to generate a url with a JWT. This is very simple but you want to make sure your application does not generate that on the page with the login link but rather a transfer thru page that generates the link then redirects the user to the ID Site URL.

ID Site Login

As an example, you have a link on your page for Login which goes go login.php. Your login.php file would include the following code which generates the JWT URL

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');	
$loginLink = $application->createIdSiteUrl(['callbackUri'=>'{CALLBACK_URI}']);
header('Location:'.$loginLink);  //or any other form of redirect to the $loginLink you want to use.

That is all you will need for generating the login link

NOTE: In order for you to be directed back to the Callback URL, you need to make sure you are explicit in the Stormpath Dashboard. Include the full url on the ID Site settings page

For the example above, you would replace {APPLICATION_ID} with the id for the applicaiton you want to allow a user to sign in to. You then replace {CALLBACK_URI} with the url you want to handle the ID Site information.

You have the ability to specify an organization nameKey as an accountStore for a login attempt and forgot password during the creation of the ID Site Url. For information on this, Visit the ID Site Guide for Multitenancy.

Ability to specify an organization nameKey as an accountStore for login attempt forgot password and id site url builder

Handle ID Site Callback

For any request you make for ID Site, you need to specify a callback uri. This is where the logic is stored for any information you want to receive from the JWT about the logged in user. To do this and get the response back from the Stormpath servers, you call the method handleIdSite on the application object while passing in the full Request URI

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');	
$response = $application->handleIdSiteCallback($_SERVER['REQUEST_URI']);	

NOTE: A JWT Response Token can only be used once. This is to prevent replay attacks. It will also only be valid for a total of 60 seconds. After which time, You will need to restart the workflow you were in.

Other ID Site Options

There are a few other methods that you will need to concern yourself with when using ID Site. Logging out a User, Registering a User, and a User who has forgotten their password. These methods will use the same information from the login method but a few more items will need to be passed into the array.

Logging Out a User

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');
$logoutLink = $application->createIdSiteUrl(['logout'=>true, 'callbackUri'=>'{CALLBACK_URI}']);
header('Location:'.$logoutLink);  //or any other form of redirect to the $loginLink you want to use.

Registering a User

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');
$registerLink = $application->createIdSiteUrl(['path'=>'/#/register','callbackUri'=>'{CALLBACK_URI}']);
header('Location:'.$registerLink);  //or any other form of redirect to the $loginLink you want to use.

Forgot Link

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');
$forgotLink = $application->createIdSiteUrl(['path'=>'/#/forgot','callbackUri'=>'{CALLBACK_URI}']);
header('Location:'.$forgotLink);  //or any other form of redirect to the $loginLink you want to use.
Using SP_Token for password reset from workflow in ID Site

We allow you to use the Workflow for password reset outside of the ID Site system, but enable you to use the password reset screens of the ID Site to do the password reset. To allow for this, you need to pass in the sp_token parameter that was provided in the email of the password reset.

$application = \Stormpath\Resource\Application::get('{APPLICATION_ID}');
$location = $application->createIdSiteUrl([
    'path'=>'/#/reset', 
    'sp_token'=>'{{SP_TOKEN}}',
    'callbackUri'=>'{{CALLBACK_URI}}'
]);
header('Location:'.$forgotLink);  //or any other form of redirect to the $loginLink you want to use.

Again, with all these methods, You will want your application to link to an internal page where the JWT is created at that time. Without doing this, a user will only have 60 seconds to click on the link before the JWT expires.

NOTE: A JWT will expire after 60 seconds of creation.

Collections

Search

Resource collections can be searched by a general query string, or by attribute or by specifying a Search object.

Passing a string to the search method will filter by any attribute on the collection:

$applications = $tenant->applications;
$applications->search = 'foo';

//Or, use the Search object

$search = new \Stormpath\Resource\Search();
$search->filter = 'foo';
$applications = $tenant->applications;
$applications->search = $search;

To search a specific attribute or attributes, pass an array:

$applications = $tenant->applications;
$applications->search = array('name' => '*foo*',
                              'description' => 'bar*',
                              'status' => 'enabled');

//Or, use the Search object

$search = new \Stormpath\Resource\Search();
$applications = $tenant->applications;
$applications->search = $search->addMatchAnywhere('name', 'foo')->
                                 addStartsWith('description', 'bar')->
                                 addEquals('status', 'enabled');

Alternatively, you can use the collection getter options to specify the search:

$applications = $tenant->getApplications(array('q' => 'foo'));

Now you can loop through the collection resource and get the results according to the specified search:

foreach($applications as $app)
{
  print $app->name;
}

Pagination

Collections can be paginated using chain-able methods (or by just using the magic setters and looping the collection). offset is the zero-based starting index in the entire collection of the first item to return. Default is 0. limit is the maximum number of collection items to return for a single request. Minimum value is 1. Maximum value is 100. Default is 25.

foreach($tenant->applications->setOffset(10)->setLimit(100) as $app)
{
  print $app->name;
}

Alternatively, you can use the collection getter options to specify the pagination:

$applications = $tenant->getApplications(array('offset' => 10, 'limit' => 100));
foreach($applications as $app)
{
  print $app->name;
}

Order

Collections can be ordered. In the following example, a paginated collection is ordered.

$applications = $tenant->applications;
$applications->order = new \Stormpath\Resource\Order(array('name'), 'desc');

Or specify the order by string:

$applications = $tenant->applications;
$applications->order = 'name desc';

Alternatively, you can use the collection getter options to specify the order:

$applications = $tenant->getApplications(array('orderBy' => 'name desc'));

Now you can loop through the collection resource and get the results according to the specified order:

foreach($applications as $app)
{
  print $app->name;
}

Entity Expansion

A resource's children can be eagerly loaded by passing the expansion string in the options argument of a call to a getter, or setting the expansion in a collection resource.

$account = \Stormpath\Resource\Account::get(
  $accountHref,
  array('expand' => 'groups,groupMemberships'));

//Or

$account = $client->
           dataStore->
           getResource($accountHref,
                      \Stormpath\Stormpath::ACCOUNT,
                      array('expand' => 'groups,groupMemberships'));

For a collection resource:

$accounts = $directory->accounts;
$expansion = new \Stormpath\Resource\Expansion();
$accounts->expansion = $expansion->addProperty('directory')->addProperty('tenant');

//Or

$accounts->expansion = 'directory,tenant';

//Or

$accounts->expansion = array('directory', 'tenant');

//Or

$accounts = $directory->getAccounts(array('expand' => 'directory,tenant'));

limit and offset can be specified for each child resource by calling addProperty.

$expansion = new \Stormpath\Resource\Expansion();
$expansion->addProperty('groups', array('offset' => 5, 'limit' => 10));
$account = \Stormpath\Resource\Account::get(
  $accountHref,
  $expansion->toExpansionArray());

//Or

$account = $client->
           dataStore->
           getResource($accountHref,
                       \Stormpath\Stormpath::ACCOUNT, $expansion->toExpansionArray());

Registering Accounts

Accounts are created on a directory instance. They can be created in two ways:

  • Directly from a directory resource:

    $account = \Stormpath\Resource\Account::instantiate(
      array('givenName' => 'John',
            'surname' => 'Smith',
            'email' => '[email protected]',
            'password' => '4P@$$w0rd!'));
    
    $directory->createAccount($account);
  • Creating it from an application resource that has a directory as the default account store:

     $application->createAccount($account);

    We can specify an additional flag to indicate if the account can skip any registration workflow configured on the directory.

    // Will skip workflow, if any
    $directory->createAccount($account, array('registrationWorkflowEnabled' => false));
    
    //Or
    
    $application->createAccount($account, array('registrationWorkflowEnabled' => false));

If the directory has been configured with an email verification workflow and a non-Stormpath URL, you have to pass the verification token sent to the URL in a sptoken query parameter back to Stormpath to complete the workflow. This is done through the verifyEmailToken static method of the Client, and an instance method with the same name on the Tenant resource.

 // this call returns an account object
 $account = \Stormpath\Client::verifyEmailToken('the_token_from_query_string');

 //Or

 // this call returns an account object
 $account = $tenant->verifyEmailToken('the_token_from_query_string');

Password Import

Stormpath now allows the importing of existing passwords. Using the modular crypt format (MCF) you can now import all your existing users over to stormpath accounts. Users must have a new account created with a password set in one of the two support mcf formats. To learn more about these formats, visit the password import product guide

To use this feature, during the account creation, just pass a second parameter to the create method.

    $account = \Stormpath\Resource\Account::instantiate(array('givenName' => 'Account Name',
                                                                  'middleName' => 'Middle Name',
                                                                  'surname' => 'Surname',
                                                                  'username' => $username,
                                                                  'email' => md5(time().microtime().uniqid()) .'@unknown123.kot',
                                                                  'password' => '$2a$08$VbNS17zvQNYtMyfRiYXxWuec2F2y3SuLB/e7hU8RWdcCxxluUB3m.'));

        self::$application->createAccount($account, array('passwordFormat'=>'mcf'));

Authentication

Authentication is accomplished by passing a username or an email and a password to authenticate of an application we've registered on Stormpath. This will either return a \Stormpath\Resource\AuthenticationResult instance if the credentials are valid, or raise a \Stormpath\Resource\ResourceError otherwise. In the former case, you can get the account associated with the credentials.

try {

    $result = $application->authenticate('johnsmith', '4P@$$w0rd!');
    $account = $result->account;

} catch (\Stormpath\Resource\ResourceError $re)
{
    print $re->getStatus();
    print $re->getErrorCode();
    print $re->getMessage();
    print $re->getDeveloperMessage();
    print $re->getMoreInfo();
}

Log In (Authenticate) an Account with Specific AccountStore

When you submit an authentication request to Stormpath, instead of executing the default login logic that cycles through account stores to find an account match, you can specify the AccountStore where the login attempt will be issued to.

At the time you create the request, it is likely that you may know the account store where the account resides, therefore you can target it directly. This will speed up the authentication attempt (especially if you have a very large number of account stores).

Example Request
$accountStore = $anAccountStoreMapping->getAccountStore();
$authenticationRequest = new UsernamePasswordRequest('usernameOrEmail', 'password', 
    array('accountStore' => $accountStore));
$result = $application->authenticateAccount($authenticationRequest);

Authenticating Against a SAML Directory

SAML is an XML-based standard for exchanging authentication and authorization data between security domains. Stormpath enables you to allow customers to log-in by authenticating with an external SAML Identity Provider.

Stormpath as a Service Provider

The specific use case that Stormpath supports is user-initiated single sign-on. In this scenario, a user requests a protected resource (e.g. your application). Your application, with the help of Stormpath, then confirms the users identity in order to determine whether they are able to access the resource. In SAML terminology, the user is the User Agent, your application (along with Stormpath) is the Service Provider, and the third-party SAML authentication site is the Identity Provider or IdP.

The broad strokes of the process are as follows:

  • User Agent requests access from Service Provider
  • Service Provider responds with redirect to Identity Provider
  • Identity Provider authenticates the user
  • Identity provider redirects user back to Service Provider along with SAML assertions.
  • Service Provider receives SAML assertions and either creates or retrieves Account information

Just like with Mirror and Social Directories, the user information that is returned from the IdP is used by Stormpath to either identify an existing Account resource, or create a new one. In the case of new Account creation, Stormpath will map the information in the response onto its own resources. In this section we will walk you through the process of configuring your SAML Directory, as well as giving you an overview of how the SAML Authentication process works.

Configuring Stormpath as a Service Provider

Configuration is stored in the Directory's Provider resource . Both of these resources must also be linked with an AccountStoreMapping. Here we will explain to you the steps that are required to configure Stormpath as a SAML Service Provider.

Step 1: Gather IDP Data

You will need the following information from your IdP:

  • SSO Login URL - The URL at the IdP to which SAML authentication requests should be sent. This is often called an "SSO URL", "Login URL" or "Sign-in URL".
  • SSO Logout URL - The URL at the IdP to which SAML logout requests should be sent. This is often called a "Logout URL", "Global Logout URL" or "Single Logout URL".
  • Signing Cert - The IdP will digitally sign auth assertions and Stormpath will need to validate the signature. This will usually be in .pem or .crt format, but Stormpath requires the text value.
  • Signing Algorithm - You will need the name of the signing algorithm that your IdP uses. It will be either "RSA-SHA256" or "RSA-SHA1".
Step 2: Configure Your SAML Directory

Input the data you gathered in Step 1 above into your Directory's Provider resource, and then pass that along as part of the Directory creation HTTP POST:

$samlProvider = \Stormpath\Resource\SamlProvider::instantiate([
            'ssoLoginUrl' => 'http://google.com/login',
            'ssoLogoutUrl' => 'http://google.com/logout',
            'encodedX509SigningCert' => $this->getDummyCertForSaml(),
            'requestSignatureAlgorithm' => 'RSA-SHA1'
        ]);

        $directory = \Stormpath\Resource\Directory::create([
            'name' => makeUniqueName('DirectoryTest samlProvider'),
            'provider' => $samlProvider
        ]);

Notice that new lines in the certificate are separated with a \n character.

Retrieve Your Service Provider Metadata

Next you will have to configure your Stormpath-powered application as a Service Provider in your Identity Provider. This means that you will need to retrieve the correct metadata from Stormpath.

In order to retrieve the required values, start by sending a GET to the Directory's Provider:

    $provider = Stormpath\Resource\SamlProvider::get(self::$directory->provider->href);
    $providerMetaData = $provider->serviceProviderMetadata

From this metadata, you will need two values:

  • Assertion Consumer Service URL: This is the location the IdP will send its response to.
  • X509 Signing Certificate: The certificate that is used to sign the requests sent to the IdP. If you retrieve XML, the certificate will be embedded. If you retrieve JSON, you'll have to follow a further /x509certificates link to retrieve it.

You will also need two other values, which will always be the same:

  • SAML Request Binding: Set to HTTP-Redirect.
  • SAML Response Binding: Set to HTTP-Post.
Step 4: Configure Your Service Provider in Your Identity Provider

Log-in to your Identity Provider (Salesforce, OneLogin, etc) and enter the information you retrieved in the previous step into the relevant application configuration fields. The specific steps to follow here will depend entirely on what Identity Provider you use, and for more information you should consult your Identity Provider's SAML documentation.

Step 5: Configure Your Application

The Stormpath Application Resource has two parts that are relevant to SAML:

  • an authorizedCallbackUri Array that defines the authorized URIs that the IdP can return your user to. These should be URIs that you host yourself.
  • an embedded samlPolicy object that contains information about the SAML flow configuration and endpoints.
    $application->setAuthorizedCallbackUris([
        'http://myapplication.com/whatever/callback',
        'http://myapplication.com/whatever/callback2'
    ]);

    $application->save();
 
Step 6: Add the SAML Directory as an Account Store

Now you last thing you have to do is map the new Directory to your Application with an Account Store Mapping.

Step 7: Configure SAML Assertion Mapping

The Identity Provider's SAML response contains assertions about the user's identity, which Stormpath can use to create and populate a new Account resource.

  <saml:AttributeStatement>
    <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
    </saml:Attribute>
    <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
    </saml:Attribute>
      <saml:Attribute Name="location" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
      <saml:AttributeValue xsi:type="xs:string">Tampa, FL</saml:AttributeValue>
    </saml:Attribute>
  </saml:AttributeStatement>

The Attribute Assertions (`<saml:AttributeStatement>`) are brought into Stormpath and become Account and customData attributes.

SAML Assertion mapping is defined in an **attributeStatementMappingRules** object found inside the Directory's Provider object, or directly: `/v1/attributeStatementMappingRules/$RULES_ID`.

##### Mapping Rules 

The rules have three different components:

- **name**: The SAML Attribute name 
- **nameFormat**: The name format for this SAML Attribute, expressed as a Uniform Resource Name (URN). 
- **accountAttributes**: This is an array of Stormpath Account or customData (`customData.$KEY_NAME`) attributes that will map to this SAML Attribute.



In order to create the mapping rules, we simply send the following:
$provider = \Stormpath\Resource\SamlProvider::get($directory->provider->href);

$ruleBuilder = new \Stormpath\Saml\AttributeStatementMappingRuleBuilder();
$rule = $ruleBuilder->setName('test1')
	->setAccountAttributes(['customData.test1'])
	->build();

$rule2 = $ruleBuilder->setName('test2')
	->setAccountAttributes(['customData.test2'])
	->build();


$rulesBuilder = new \Stormpath\Saml\AttributeStatementMappingRulesBuilder();
$rulesBuilder->setAttributeStatementMappingRules([$rule, $rule2]);
$rules = $rulesBuilder->build();

$provider->setAttributeStatementMappingRules($rules);

$provider->save();


### Verify an Account's email address

This workflow allows you to send a welcome email to a newly registered account and optionally verify that they own the 
email addressed used during registration.

The email verification workflow involves changes to an account at an application level, and as such, this workflow
relies on the account resource as a starting point. This workflow is disabled by default for accounts, but you can 
enable it one of two ways.  The first way is to log into the Admin Console UI. Refer to the Stormpath Admin Console 
product guide for complete instructions on how to do this.  The second way is via the SDK.  

After creating or getting a directory, you will have access to the `accountCreationPolicy` object.

```php
    $directory = \Stormpath\Resource\Group::get($directoryHref);
    $accountCreationPolicy = $directory->accountCreationPolicy;

You can then interact with the policy resource like any other resource and set the status with either Stormpath::ENABLED or Stormpath::DISABLED

     $accountCreationPolicy->verificationEmailStatus = Stormpath::ENABLED;
     $accountCreationPolicy->verificationSuccessEmailStatus = Stormpath::ENABLED;
     $accountCreationPolicy->welcomeEmailStatus = Stormpath::ENABLED;
     
     $accountCreationPolicy->save();

Resending the verification email

In some cases, it may be needed to resend the verification email. This could be because the user accidentally deleted the verification email or it was undeliverable at a certain time. An Application has the ability to resend verification emails based on the account’s username or email.

Resend Email Verification Resource Attributes
  • login : Either the email or username for the account that needs an email verification resent
  • accountStore : An optional link to the application’s accountStore (directory or group) that you are certain contains the account attempting to resend the verification email to.
Execute Email Verification Resend
$application->sendVerificationEmail('[email protected]');

If the verification email is queued to be sent, a 202 ACCEPTED response is returned by the server. However, the sendVerificationEmail method does not return any value.

Alternatively, it is possible to specify the accountStore where the user account that needs verification resides as a performance enhancement.

$directory = \Stormpath\Resource\Directory::get('https://api.stormpath.com/v1/directories/2k1eykEKqVok365Ue2Y2T1');
$application->sendVerificationEmail('[email protected]', array('accountStore' => $directory));

Password Reset

A password reset workflow, if configured on the directory the account is registered on, can be kicked off with the sendPasswordResetEmail method on an application:

// this method returns the account
$account = $application->sendPasswordResetEmail('[email protected]');

// if you want the SP Token to be returned
$account = $application->sendPasswordResetEmail('[email protected]', [], true);

Alternatively, if you know the account store where the account matching the specified email address resides, you can include it as part of the $options array in the call to sendPasswordResetEmail. This is useful as a performance enhancement if the application might be mapped to many (dozens, hundreds or thousands) of account stores, a common scenario in multi-tenant applications.

$accountStore = $anAccountStoreMapping->getAccountStore();
// this method returns the account
$account = $application->sendPasswordResetEmail('[email protected]', 
    array('accountStore' => $accountStore);

If the workflow has been configured to verify through a non-Stormpath URL, you can verify the token sent in the query parameter sptoken with the verifyPasswordResetToken method on the application.

// this method returns the account
$account = $application->verifyPasswordResetToken('the_token_from_query_string');

With the account acquired you can then update the password:

  $account = $application->resetPassword($sptoken, $newPassword);

NOTE : Confirming a new password is left up to the web application code calling the Stormpath SDK. The SDK does not require confirmation.

ACL through Groups

Memberships of accounts in certain groups can be used as an authorization mechanism. As the groups collection property on an account instance can be searched, you can seek for the group to determine the account is associated with it:

$isAdmin = false;
$search = array('name' => 'Admins');

foreach($account->groups->setSearch($search) as $group)
{
    // if one group was returned, the account is
    // in the group based on the search criteria
    $isAdmin = true;
}

You can create groups and assign them to accounts using the Stormpath web console, or programmatically. Groups are created on directories:

$group = \Stormpath\Resource\Group::instantiate(
    array('name' => 'Admins', 'description' => 'Admins Group'));

// Or
$group = $client->dataStore->instantiate(\Stormpath\Stormpath::GROUP);
$group->name = 'Admins';
$group->description = 'Admins Group';

$directory->createGroup($group);

Group membership can be created by:

  • Explicitly creating a group membership from its resource class:

    // the $account and $group variables must be actual
    // resource instances of their corresponding types
    $groupMembership = \Stormpath\Resource\GroupMembership::create(
      array('account' => $account, 'group' => $group));
  • Using the addGroup method on the account instance:

    $account->addGroup($group);
  • Using the addAccount method on the group instance:

    $group->addAccount($account);

Integrating with Google

Stormpath supports accessing accounts from a number of different locations including Google. Google uses OAuth 2.0 protocol for authentication / authorization and Stormpath can leverage their authorization code (or access tokens) to return an Account for a given code.

The steps to enable this functionality into your application include:

  • Create a Google Directory
  • Create an AccountStoreMapping between a Google Directory and your Application
  • Accessing Accounts with Google Authorization Codes or Access Tokens

Google Directories follow behavior similar to mirror directories, but have a Provider resource that contains information regarding the Google application that the directory is configured for.

Google Provider Resource

A GoogleProvider resource holds specific information needed for working with a Google Directory. It is important to understand the format of the provider resource when creating and updating a Google Directory.

A provider resource can be obtained by accessing the directory’s provider as follows:

$provider = $client->dataStore->getResource("directories/{{$directoryID}}/provider",
    \Stormpath\Stormpath::GOOGLE_PROVIDER);

or, by means of the directory Resource:

$provider = $directory->getProvider();

Alternatively, it is possible to use the static client configuration to the get the Provider:

// It is also possible to specify the URL ending with "/provider", 
// or the partial path (which could be "directories/DIR_ID/provider", 
// or "DIR_ID/provider" or just "DIR_ID"). 
$directoryHref = "https://api.stormpath.com/v1/directories/1mBDmVgW8JEon4AkoSYjPv"; 
$provider = GoogleProvider::get($directoryHref);
Resource Attributes
  • clientId : The App ID for your Google application
  • clientSecret : The App Secret for your Google application
  • redirectUri : The redirection Uri for your Google application
  • providerId : The provider ID is the Stormpath ID for the Directory’s account provider

In addition to your application specific attributes, a Provider resource will always contain 3 reserved read-only fields:

  • href : The fully qualified location of the custom data resource
  • createdAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string
  • modifiedAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string

Creating a Google Directory

Creating a Google Directory requires that you gather some information beforehand from Google’s Developer Console regarding your application.

  • Client ID
  • Client Secret
  • Redirect URI

Creating a Google Directory is very similar to creating a directory within Stormpath. For a Google Directory to be configured correctly, you must specify the correct Provider information.

$provider = Stormpath\Resource\GoogleProvider::instantiate([
  'clientId' => '857385-m8vk0fn2r7jmjo.apps.googleusercontent.com',
  'clientSecret' => 'ehs7_-bA7OWQSQ4',
  'redirectUri' => 'https://myapplication.com/authenticate'
  ]);

$directory = Stormpath\Resource\Directory::instantiate([
  'name' => 'A Google Directory',
  'description' => 'My Google Directory',
  'provider' => $provider
  ]);

$tenant = $client->tenant;
$directory = $tenant->createDirectory($directory);

OR

$provider = $client->dataStore->instantiate(\Stormpath\Stormpath::GOOGLE_PROVIDER);
$provider->clientId = "857385-m8vk0fn2r7jmjo.apps.googleusercontent.com";
$provider->clientSecret = "ehs7_-bA7OWQSQ4";
$provider->redirectUri = "https://myapplication.com/authenticate";

$directory = $client->dataStore->instantiate(\Stormpath\Stormpath::DIRECTORY);
$directory->name = "my-google-directory";
$directory->description = "A Google directory";
$directory->provider = $provider;

$tenant = $client->getCurrentTenant();
$directory = $tenant->createDirectory($directory);

After the Google Directory has been created, it needs to be mapped with an application as an account store. The Google Directory cannot be a default account store or a default group store. Once the directory is mapped as an account store for an application, you are ready to access Accounts with Google Authorization Codes.

Accessing Accounts with Google Authorization Codes or Access Tokens

To access or create an account in an already created Google Directory, it is required to gather a Google Authorization Code on behalf of the user. This requires leveraging Google’s OAuth 2.0 protocol and the user’s consent for your application’s permissions.

Once the Authorization Code is gathered, you can get or create the Account by means of the Application and specifying a ProviderRequest. The following example shows how you use GoogleProviderAccountRequest to get an Account for a given authorization code:

$applicationHref = "https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu";
$application = $client->getResource(applicationHref, \Stormpath\Stormpath::APPLICATION);
$providerRequest = new GoogleProviderAccountRequest(array(
    "code" => "4/a3p_fn0sMDQlyFVTYwfl5GAj0Obd.oiruVLbQZSwU3oEBd8DOtNApQzTCiwI"
));

$result = $application->getAccount($providerRequest);
$account = $result->getAccount();

In order to know if the account was created or if it already existed in the Stormpath’s Google Directory you can do: result.isNewAccount();. It will return true if it is a newly created account; false otherwise.

Once an Account is retrieved, Stormpath maps common fields for the Google User to the Account. The access token and the refresh token for any additional calls in the GoogleProviderData resource and can be retrieved by:

$providerData = $account->getProviderData();

The returned GoogleProviderData includes:

$providerData->accessToken; //-> y29.1.AADN_Xo2hxQflWwsgCSK-WjSw1mNfZiv4
$providerData->createdAt; //-> 2014-04-01T17:00:09.154Z 
$providerData->href; //-> https://api.stormpath.com/v1/accounts/ciYmtETytH0tbHRBas1D5/providerData 
$providerData->modifiedAt; //-> 2014-04-01T17:00:09.189Z 
$providerData->providerId; //-> google 
$providerData->refreshToken; //-> 1/qQTS638g3ArE4U02FoiXL1yIh-OiPmhc

The accessToken can also be passed as a field for the ProviderData to access the account once it is retrieved:

$providerRequest = new GoogleProviderRequest(array(
    "accessToken" =>"y29.1.AADN_Xo2hxQflWwsgCSK-WjSw1mNfZiv4"
));
$result = $application->getAccount(request);
$account = $result->getAccount();

The refreshToken will only be present if your application asked for offline access. Review Google’s documentation for more information regarding OAuth offline access.

Integrating with Facebook

Stormpath supports accessing accounts from a number of different locations including Facebook. Facebook uses OAuth 2.0 protocol for authentication / authorization and Stormpath can leverage their or access tokens to return an Account for a given code.

The steps to enable this functionality into your application include:

  • Create a Facebook Directory
  • Create an Account Store Mapping between a Facebook Directory and your Application
  • Accessing Accounts with Facebook User Access Tokens

Facebook Directories follow behavior similar to mirror directories, but have a Provider resource that contains information regarding the Facebook application that the directory is configured for.

FACEBOOK PROVIDER RESOURCE

A FacebookProvider resource holds specific information needed for working with a Facebook Directory. It is important to understand the format of the provider resource when creating and updating a Facebook Directory.

A provider resource can be obtained by accessing the directory’s provider as follows:

Example Request

$provider = $client->dataStore->getResource("directories/72N2MjJSIXuln56sNngcvr/provider",
    \Stormpath\Stormpath::FACEBOOK_PROVIDER);

or, by means of the directory Resource:

$provider = $directory->getProvider();

Alternatively, it is possible to use the static client configuration to the get the Provider:

// It is also possible to specify the URL ending with "/provider", 
// or the partial path (which could be "directories/DIR_ID/provider", 
// or "DIR_ID/provider" or just "DIR_ID"). 
$directoryHref = "https://api.stormpath.com/v1/directories/1mBDmVgW8JEon4AkoSYjPv"; 
$provider = FacebookProvider::get($directoryHref);
Resource Attributes
  • clientId : The App ID for your Facebook application
  • clientSecret : The App Secret for your Facebook application
  • providerId : The provider ID is the Stormpath ID for the Directory’s account provider

In addition to your application specific attributes, a Provider resource will always contain 3 reserved read-only fields:

  • href : The fully qualified location of the custom data resource
  • createdAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string
  • modifiedAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string

CREATING A FACEBOOK DIRECTORY

Creating a Facebook Directory requires that you gather some information beforehand from Facebook’s Developer Console regarding your application.

  • Client ID
  • Client Secret

Creating a Facebook Directory is very similar to creating a directory within Stormpath. For a Facebook Directory to be configured correctly, you must specify the correct Provider information.

Example Request

$provider = Stormpath\Resource\FacebookProvider::instantiate([
  'clientId' => '1011854538839621',
  'clientSecret' => '82c16954b0d88216127d66ac44bbc3a8'
  ]);

$directory = Stormpath\Resource\Directory::instantiate([
  'name' => 'A Facebook Directory',
  'description' => 'My Facebook Directory',
  'provider' => $provider
  ]);

$tenant = $client->tenant;
$directory = $tenant->createDirectory($directory);

OR

$provider = $client->dataStore->instantiate(\Stormpath\Stormpath::FACEBOOK_PROVIDER);
$provider->clientId = "1011854538839621";
$provider->clientSecret = "82c16954b0d88216127d66ac44bbc3a8";

$directory = $client->dataStore->instantiate(\Stormpath\Stormpath::DIRECTORY);
$directory->name = "my-fb-directory";
$directory->description = "A Facebook directory";
$directory->provider = $provider;

$tenant = $client->getCurrentTenant();
$directory = $tenant->createDirectory($directory);

After the Facebook Directory has been created, it needs to be mapped with an application as an account store. The Facebook Directory cannot be a default account store or a default group store. Once the directory is mapped to an account store for an application, you are ready to access Accounts with Facebook User Access Tokens.

ACCESSING ACCOUNTS WITH FACEBOOK USER ACCESS TOKENS

To access or create an account in an already created Facebook Directory, it is required to gather the User Access Token on behalf of the user. This usually requires leveraging Facebook’s javascript library and the user’s consent for your application’s permissions.

It is required that your Facebook application request for the email permission from Facebook. If the access token does not grant email permissions, you will not be able to get an Account with an access token.

Once the Authorization Code is gathered, you can get or create the Account by means of the Application and specifying its ProviderData. The following example shows how you use FacebookProviderAccountRequest to get an Account for a given authorization code:

Example Request

$applicationHref = "https://api.stormpath.com/v1/applications/2k1aegw9UbLX4ZfMH4kCkR";
$application = \Stormpath\Resource\Application::get($applicationHref);

$providerAccountRequest = new \Stormpath\Provider\FacebookProviderAccountRequest(array(
    "accessToken" => "CABTmZxAZBxBADbr1l7ZCwHpjivBt9T0GZBqjQdTmgyO0OkUq37HYaBi4F23f49f5"
));

$result = $application->getAccount($providerRequest);
$account = $result->getAccount();

In order to know if the account was created or if it already existed in the Stormpath’s Facebook Directory you can do: $result->isNewAccount();. It will return true if it is a newly created account; false otherwise.

Once an Account is retrieved, Stormpath maps common fields for the Facebook User to the Account. The access token for any additional calls in the FacebookProviderData resource and can be retrieved by:

$providerData = $account->getProviderData();

The returned FacebookProviderData will include:

$providerData->accessToken; //-> CABTmZxAZBxBADbr1l7ZCwHpjivBt9T0GZBqjQdTmgyO0OkUq37HYaBi4F23f49f5
$providerData->createdAt; //-> 2014-04-01T17:00:09.154Z
$providerData->href; //-> https://api.stormpath.com/v1/accounts/ciYmtETytH0tbHRBas1D5/providerData
$providerData->modifiedAt; //-> 2014-04-01T17:00:09.189Z
$providerData->providerId; //-> facebook

Integrating with Github

Stormpath supports accessing accounts from a number of different locations including Github. Github uses OAuth 2.0 protocol for authentication / authorization and Stormpath can leverage their authorization code (or access tokens) to return an Account for a given code.

The steps to enable this functionality into your application include:

  • Create a Github Directory
  • Create an AccountStoreMapping between a Github Directory and your Application
  • Accessing Accounts with Google Authorization Codes or Access Tokens

Github Directories follow behavior similar to mirror directories, but have a Provider resource that contains information regarding the Github application that the directory is configured for.

Github Provider Resource

A GithubProvider resource holds specific information needed for working with a Github Directory. It is important to understand the format of the provider resource when creating and updating a Github Directory.

A provider resource can be obtained by accessing the directory’s provider as follows:

$provider = $client->dataStore->getResource("directories/1mBDmVgW8JEon4AkoSYjPv/provider",
    \Stormpath\Stormpath::GITHUB_PROVIDER);

or, by means of the directory Resource:

$provider = $directory->getProvider();

Alternatively, it is possible to use the static client configuration to the get the Provider:

// It is also possible to specify the URL ending with "/provider", 
// or the partial path (which could be "directories/DIR_ID/provider", 
// or "DIR_ID/provider" or just "DIR_ID"). 
$directoryHref = "https://api.stormpath.com/v1/directories/1mBDmVgW8JEon4AkoSYjPv"; 
$provider = GithubProvider::get($directoryHref);
Resource Attributes
  • clientId : The App ID for your Github application
  • clientSecret : The App Secret for your Github application
  • providerId : The provider ID is the Stormpath ID for the Directory’s account provider

In addition to your application specific attributes, a Provider resource will always contain 3 reserved read-only fields:

  • href : The fully qualified location of the custom data resource
  • createdAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string
  • modifiedAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string

Creating a Github Directory

Creating a Github Directory requires that you gather some information beforehand from your Github developers settings regarding your application.

  • Client ID
  • Client Secret

Creating a Github Directory is very similar to creating a directory within Stormpath. For a Github Directory to be configured correctly, you must specify the correct Provider information.

$provider = Stormpath\Resource\GithubProvider::instantiate([
  'clientId' => '48f983a65887df76',
  'clientSecret' => '2b5476584adf7846f890094cba3672f7'
  ]);

$directory = Stormpath\Resource\Directory::instantiate([
  'name' => 'A Github Directory',
  'description' => 'My Github Directory',
  'provider' => $provider
  ]);

$tenant = $client->tenant;
$directory = $tenant->createDirectory($directory);

OR

$provider = $client->dataStore->instantiate(\Stormpath\Stormpath::GITHUB_PROVIDER);
$provider->clientId = "48f983a65887df76";
$provider->clientSecret = "2b5476584adf7846f890094cba3672f7";

$directory = $client->dataStore->instantiate(\Stormpath\Stormpath::DIRECTORY);
$directory->name = "my-github-directory";
$directory->description = "A Github directory";
$directory->provider = $provider;

$tenant = $client->getCurrentTenant();
$directory = $tenant->createDirectory($directory);

After the Github Directory has been created, it needs to be mapped with an application as an account store. The Github Directory cannot be a default account store or a default group store. Once the directory is mapped as an account store for an application, you are ready to access Accounts with Github Authorization Codes.

Accessing Accounts with Github Authorization Codes or Access Tokens

To access or create an account in an already created Google Directory, it is required to gather a Google Authorization Code on behalf of the user. This requires leveraging Google’s OAuth 2.0 protocol and the user’s consent for your application’s permissions.

Once the Authorization Code is gathered, you can get or create the Account by means of the Application and specifying a ProviderRequest. The following example shows how you use GoogleProviderAccountRequest to get an Account for a given authorization code:

$applicationHref = "https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu";
$application = $client->getResource(applicationHref, \Stormpath\Stormpath::APPLICATION);
$providerRequest = new GithubProviderAccountRequest(array(
    "code" => "fn0sMDQlyFVTYwfl5GAj0Obd"
));

$result = $application->getAccount($providerRequest);
$account = $result->getAccount();

In order to know if the account was created or if it already existed in the Stormpath’s Google Directory you can do: $result->isNewAccount();. It will return true if it is a newly created account; false otherwise.

Once an Account is retrieved, Stormpath maps common fields for the Github User to the Account. The access token and the refresh token for any additional calls in the GithubProviderData resource and can be retrieved by:

$providerData = $account->getProviderData();

The returned GithubProviderData includes:

$providerData->accessToken; //-> y29.1.AADN_Xo2hxQflWwsgCSK-WjSw1mNfZiv4
$providerData->createdAt; //-> 2014-04-01T17:00:09.154Z 
$providerData->href; //-> https://api.stormpath.com/v1/accounts/ciYmtETytH0tbHRBas1D5/providerData 
$providerData->modifiedAt; //-> 2014-04-01T17:00:09.189Z 
$providerData->providerId; //-> github 
$providerData->refreshToken; //-> 1/qQTS638g3ArE4U02FoiXL1yIh-OiPmhc

The accessToken can also be passed as a field for the ProviderData to access the account once it is retrieved:

$providerRequest = new GithubProviderRequest(array(
    "accessToken" =>"fn0sMDQlyFVTYwfl5GAj0Obd"
));
$result = $application->getAccount(request);
$account = $result->getAccount();

The refreshToken will only be present if your application asked for offline access. Review Github’s documentation for more information regarding OAuth offline access.

Integrating with LinkedIn

Stormpath supports accessing accounts from a number of different locations including LinkedIn. LinkedIn uses OAuth 2.0 protocol for authentication / authorization and Stormpath can leverage their authorization code (or access tokens) to return an Account for a given code.

The steps to enable this functionality into your application include:

  • Create a LinkedIn Directory
  • Create an AccountStoreMapping between a LinkedIn Directory and your Application
  • Accessing Accounts with LinkedIn Authorization Codes or Access Tokens

LinkedIn Directories follow behavior similar to mirror directories, but have a Provider resource that contains information regarding the LinkedIn application that the directory is configured for.

LinkedIn Provider Resource

A LinkedInProvider resource holds specific information needed for working with a LinkedIn Directory. It is important to understand the format of the provider resource when creating and updating a LinkedIn Directory.

A provider resource can be obtained by accessing the directory’s provider as follows:

$provider = $client->dataStore->getResource("https://api.stormpath.com/v1/directories/1mBDmVgW8JEon4AkoSYjPv/provider",
    \Stormpath\Stormpath::LINKEDIN_PROVIDER);

or, by means of the directory Resource:

$provider = $directory->getProvider();

Alternatively, it is possible to use the static client configuration to the get the Provider:

// It is also possible to specify the URL ending with "/provider", 
// or the partial path (which could be "directories/DIR_ID/provider", 
// or "DIR_ID/provider" or just "DIR_ID"). 
$directoryHref = "https://api.stormpath.com/v1/directories/1mBDmVgW8JEon4AkoSYjPv"; 
$provider = LinkedInProvider::get($directoryHref);
Resource Attributes
  • clientId : The App ID for your LinkedIn application
  • clientSecret : The App Secret for your LinkedIn application
  • providerId : The provider ID is the Stormpath ID for the Directory’s account provider

In addition to your application specific attributes, a Provider resource will always contain 3 reserved read-only fields:

  • href : The fully qualified location of the custom data resource
  • createdAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string
  • modifiedAt : the UTC timestamp with millisecond precision of when the resource was created in Stormpath as an ISO 8601 formatted string

Creating a LinkedIn Directory

Creating a LinkedIn Directory requires that you gather some information beforehand from LinkedIn’s Developer Console regarding your application.

  • Client ID
  • Client Secret

Creating a LinkedIn Directory is very similar to creating a directory within Stormpath. For a LinkedIn Directory to be configured correctly, you must specify the correct Provider information.

$provider = Stormpath\Resource\LinkedInProvider::instantiate([
  'clientId' => '857385m8vk0fn2r7j',
  'clientSecret' => 'ehs7bA7OWQSQ4'
  ]);

$directory = Stormpath\Resource\Directory::instantiate([
  'name' => 'A LinkedIn Directory',
  'description' => 'My LinkedIn Directory',
  'provider' => $provider
  ]);

$tenant = $client->tenant;
$directory = $tenant->createDirectory($directory);

OR

$provider = $client->dataStore->instantiate(\Stormpath\Stormpath::LINKEDIN_PROVIDER);
$provider->clientId = "857385m8vk0fn2r7j";
$provider->clientSecret = "ehs7bA7OWQSQ4";

$directory = $client->dataStore->instantiate(\Stormpath\Stormpath::DIRECTORY);
$directory->name = "my-linkedin-directory";
$directory->description = "A LinkedIn directory";
$directory->provider = $provider;

$tenant = $client->getCurrentTenant();
$directory = $tenant->createDirectory($directory);

After the LinkedIn Directory has been created, it needs to be mapped with an application as an account store. The LinkedIn Directory cannot be a default account store or a default group store. Once the directory is mapped as an account store for an application, you are ready to access Accounts with LinkedIn Authorization Codes.

Accessing Accounts with LinkedIn Authorization Codes or Access Tokens

To access or create an account in an already created LinkedIn Directory, it is required to gather a LinkedIn Authorization Code on behalf of the user. This requires leveraging LinkedIn’s OAuth 2.0 protocol and the user’s consent for your application’s permissions.

Once the Authorization Code is gathered, you can get or create the Account by means of the Application and specifying a ProviderRequest. The following example shows how you use LinkedInProviderAccountRequest to get an Account for a given authorization code:

$applicationHref = "https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu";
$application = $client->getResource(applicationHref, \Stormpath\Stormpath::APPLICATION);
$providerRequest = new LinkedInProviderAccountRequest(array(
    "code" => "4/a3p_fn0sMDQlyFVTYwfl5GAj0Obd.oiruVLbQZSwU3oEBd8DOtNApQzTCiwI"
));

$result = $application->getAccount($providerRequest);
$account = $result->getAccount();

In order to know if the account was created or if it already existed in the Stormpath’s Google Directory you can do: $result->isNewAccount();. It will return true if it is a newly created account; false otherwise.

Once an Account is retrieved, Stormpath maps common fields for the Google User to the Account. The access token and the refresh token for any additional calls in the LinkedInProviderData resource and can be retrieved by:

$providerData = $account->getProviderData();

The returned LinkedInProviderData includes:

$providerData->accessToken; //-> y29.1.AADN_Xo2hxQflWwsgCSK-WjSw1mNfZiv4
$providerData->createdAt; //-> 2014-04-01T17:00:09.154Z 
$providerData->href; //-> https://api.stormpath.com/v1/accounts/ciYmtETytH0tbHRBas1D5/providerData 
$providerData->modifiedAt; //-> 2014-04-01T17:00:09.189Z 
$providerData->providerId; //-> linkedin 
$providerData->refreshToken; //-> 1/qQTS638g3ArE4U02FoiXL1yIh-OiPmhc

The accessToken can also be passed as a field for the ProviderData to access the account once it is retrieved:

$providerRequest = new LinkedInProviderRequest(array(
    "accessToken" =>"y29.1.AADN_Xo2hxQflWwsgCSK-WjSw1mNfZiv4"
));
$result = $application->getAccount(request);
$account = $result->getAccount();

The refreshToken will only be present if your application asked for offline access. Review LinkedIn’s documentation for more information regarding OAuth offline access.

Using Stormpath for API Authentication

Create an Account for your developers

First, you will need user accounts in Stormpath to represent the people that are developing against your API. Accounts can not only represent Developers, but also can be used to represent services, daemons, processes, or any “entity” that needs to login to a Stormpath-secured API.

$account = \Stormpath\Resource\Account::instantiate(
  array('givenName' => 'Joe',
        'surname' => 'Stormtrooper',
        'email' => '[email protected]',
        'password' => 'Changeme1'));

$application->createAccount($account);

Create and Manage API Keys for an Account

After you create an account for a developer, you will need to generate an API Key (or multiple) to be used when accessing your API. Each account will have an apiKeys property that contains a collection of their API Keys. There will also be a list of API keys on a account’s profile in the Stormpath Admin Console. You will be able to both create and manage keys in both.

CREATING API KEYS FOR AN ACCOUNT

$apiKey = $account->createApiKey();

$apiKeyId = $apikey->id;
$apiKeySecret = $apikey->secret;

The ApiKey returned will have the following properties:

  • id The unique identifier for the API Key
  • secret The secret for the API key.
  • status A property that represent the status of the key. Keys with a disabled status will not be able to authenticate.
  • account A link to the ApiKey’s account.
  • tenant A link to the ApiKey’s tenant.

MANAGE API KEYS FOR AN ACCOUNT

Deleting an API Key
$apiKeyId = 'FURThLWDE4MElDTFVUMDNDTzpQSHozZ';
$apiKey = $application->getApiKey($apiKeyId);
$apiKey->delete();
Disable an API key
$apiKeyId = 'FURThLWDE4MElDTFVUMDNDTzpQSHozZ' 
$apiKey = $application->getApiKey('FURThLWDE4MElDTFVUMDNDTzpQSHozZ');
$apiKey->status = 'DISABLED';
$apiKey->save()

Using the Stormpath SDK to Authenticate and Generate Tokens for your API Keys

The class ApiRequestAuthenticator can be used to perform both Basic Authentication and OAuth Authentication.

Basic Authentication

GET /troopers/tk421/equipment 
Accept: application/json
Authorization: Basic MzRVU1BWVUFURThLWDE4MElDTFVUMDNDTzpQSHozZitnMzNiNFpHc1R3dEtOQ2h0NzhBejNpSjdwWTIwREo5N0R2L1g4
Host: api.trooperapp.com

The Authorization header contains a base64 encoding of the API Key and Secret.

Using ApiRequestAuthenticator

$application = \Stormpath\Resource\Application::get("https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu");

$request = \Stormpath\Authc\Api\Request::createFromGlobals();
$result = (new \Stormpath\Authc\Api\ApiRequestAuthenticator($application))->authenticate($request);

$account = $result->getApiKey()->account;
$apiKey = $result->getApiKey();
Using BasicRequestAuthenticator
$application = \Stormpath\Resource\Application::get("https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu");

$request = \Stormpath\Authc\Api\Request::createFromGlobals();
$result = (new BasicRequestAuthenticator($application))->authenticate($request);

$account = $result->getApiKey()->account;
$apiKey = $result->getApiKey();

OAuth Authentication

GENERATING A TOKEN

POST /oauth/token
Accept: application/json
Authorization: Basic MzRVU1BWVUFURThLWDE4MElDTFVUMDNDTzpQSHozZitnMzNiNFpHc1
Content-Type: application/x-www-form-urlencoded
Host: api.trooperapp.com

  grant_type=client_credentials

The Authorization header contains a base64 encoding of the API Key and Secret.

$application = \Stormpath\Resource\Application::get("https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu");

$request = \Stormpath\Authc\Api\Request::createFromGlobals();
$result = new ApiRequestAuthenticator($application)->authenticate($request);

$tokenResponse = $result->tokenResponse;
$token = $tokenResponse->accessToken;
$json = $tokenResponse->toJson();

Alternatively, it's possible to use OAuthRequestAuthenticator or the more specific authenticator OAuthClientCredentialsRequestAuthenticator to generate access tokens.

The response including the access token looks like this:

HTTP 200 OK
Content-Type: application/json

{
   "access_token":"7FRhtCNRapj9zs.YI8MqPiS8hzx3wJH4.qT29JUOpU64T",
   "token_type":"bearer",
   "expires_in":3600
}

AUTHENTICATION USING TOKEN

GET /troopers/tk421/equipment 
Accept: application/json
Authorization: Bearer 7FRhtCNRapj9zs.YI8MqPiS8hzx3wJH4.qT29JUOpU64T
Host: api.trooperapp.com
$application = \Stormpath\Resource\Application::get("https://api.stormpath.com/v1/applications/24mp4us71ntza6lBwlu");

$request = \Stormpath\Authc\Api\Request::createFromGlobals();
$result = (new OAuthRequestAuthenticator($application))->authenticate($request);

$account = $result->getApiKey()->account;
$apiKey = $result->getApiKey();

You can also use the more specific OAuthBearerRequestAuthenticator to authenticate token access requests.

Password and Refresh Token Grant types

For details on Token Management and authenticating with Password Access Tokens and Refreshing the access tokens, View our Stormpath Token Management Product Guide

Run the tests

In order to run the tests you need to clone the repository, install the dependencies via composer and configure the api key file location. These tests require that your computer is able to communicate with the Stormpath REST API, as they perform requests to the Stormpath servers.

To perform the installation:

git clone https://github.com/stormpath/stormpath-sdk-php.git
cd stormpath-sdk-php && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev

Now configure the api key file location and run the tests:

export STORMPATH_SDK_TEST_API_KEY_FILE_LOCATION=/path/to/file/apiKey.properties
vendor/bin/phpunit

Alternatively, configure the api key id and secret and run the tests:

export STORMPATH_SDK_TEST_API_KEY_ID=API_KEY_ID_VALUE
export STORMPATH_SDK_TEST_API_KEY_SECRET=API_KEY_SECRET_VALUE
vendor/bin/phpunit

If you would like code coverage, please run the tests with the following:

vendor/bin/phpunit --coverage-html=./code-coverage

The code coverage will be placed in the root of the package in a folder named code-coverage. Once you have this folder, you can open it in your browser to view it.

Contributing

You can make your own contributions by forking the dev branch, making your changes, and issuing pull-requests on the dev branch.

Quick Class Diagram

+-------------+
| Application |
|             |
+-------------+
       + 1
       |
       |        +------------------------+
       |        |     AccountStore       |
       o- - - - |                        |
       |        +------------------------+
       |                     ^ 1..*
       |                     |
       |                     |
       |          +---------OR---------+
       |          |                    |
       |          |                    |
       v 0..*   1 +                    + 1
+---------------------+            +--------------+
|      Directory      | 1        1 |    Group     |1
|                     |<----------+|              |+----------+
|                     |            |              |           |
|                     | 1     0..* |              |0..*       |
|                     |+---------->|              |<-----+    |
|                     |            +--------------+      |    |         +-----------------+
|                     |                                  |    |         | GroupMembership |
|                     |                                  o- - o - - - - |                 |
|                     |            +--------------+      |    |         +-----------------+
|                     | 1     0..* |   Account    |1     |    |
|                     |+---------->|              |+-----+    |
|                     |            |              |           |
|                     | 1        1 |              |0..*       |
|                     |<----------+|              |<----------+
+---------------------+            +--------------+

Copyright & Licensing

Copyright © 2013 Stormpath, Inc. and contributors.

This project is licensed under the Apache 2.0 Open Source License.

For additional information, please see the full Project Documentation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.