sentry manual v1

Upload: carlosroec

Post on 13-Oct-2015

49 views

Category:

Documents


0 download

TRANSCRIPT

  • Sentry is a simple, easy to use

    authorization and authentication

    package built for FuelPHP.

    FeaturesIt also provides additional features such as user groups and additional security features.

    Authentication (via username or email)

    Authorization

  • Groups / Roles

    Remember Me

    User Suspension / Login Attempt Limiter

    Password Reset

    User Activation

    User Metadata

    Download

    Download Sentry into your FuelPHP's packages directory. You can download the latest version of Sentryvia zip here or pull directly from the repository with the following command within the 'fuel/packages/'directory.

  • Download

    $ git clone -b master [email protected]:cartalyst/sentry-fuel.git sentry

    Installation

    Once downloaded, you may want to add sentry to the always load packages array in 'app/config.php'.Installing the tables is as simple as running an oil migration.

    Default table names are: users, users_metadata, groups, user_groups and users_suspended.

    Notes: Your database connection needs to be setup first. The DB_Util code can be found

    in sentry/migrations if you can not install via oil for some reason. If you wish to change

    the default table names, you may adjust them in the configuration file.

    $ php oil r migrate --packages=sentry

  • ConfigurationSentry has a few configuration options you may wish to adjust besides just the table names mentionedabove.

    Database Instance

    Login Column

    Remember Me

    Session

    Suspension / Limit Attempts

    Database Instance

    Sentry allows you to set a specific database instance for Sentry to connect to.

    Option Type Default Description

  • db_instance string null Name of database instance, or null for the default FuelPHP instance.

    Login Column

    Sentry allows you to pick your login column to either be username or email. This option is easy to adjustin the configuration.

    Notes: Whichever option you pick, email will always be required. Both will always need

    to be unique.

    Option Type Default Description

    login_column string email Name of login column, either email or username.

    Remember Me

    Remember me sets a cookie to keep the user logged in for a designated length of time. This featurecontains the following options.

    Option Type Default Description

    cookie_name string sentry_rm The cookies name

  • expiration int 1209600 // 2 weeks The amount of time the cookie should be set for in seconds.

    Session

    Sets the session keys for retrieving the Sentry data.

    Option Type Default Description

    user string sentry_user Sets the session key to retrieve the Sentry User.

    provider string sentry_provider Sets the session key to retrieve the Sentry Provider.

    Suspension / Limit Attempts

    Sentry has included an additional security feature to limit the amount of attempts a user/ip combo can makewithin a certain timeframe.

    Option Type Default Description

    enabled bool true Used to enable/disable the suspension feature

    attempts integer 5 The number of attempts allowed before the user is suspended

    time intenger 15 The length of time the account should be suspended for in minutes.

  • Authentication user()

    login()

    force_login()

    logout()

    check()

    activate_user()

    reset_password()

    reset_password_confirm()

    user($id = null, $recache = false)

    The user method returns a Sentry_User object.

  • Parameters

    Param Type Default Description

    $id int|string null

    The users id (int) or login column value (string).If null, the current logged in user is selected.If there is no user logged in, a blank user object isreturned.

    $recache bool false Recache the selected user object.

    Returns Sentry_User

    Throws SentryAuthException

    Examples:

    // select a user by idtry{ $user = Sentry::user(12);

    // select a user by login column $user = Sentry::user('[email protected]');

    // get the current logged in user or an empty user $user = Sentry::user();}

  • catch (SentryAuthException $e){ $error = $e->getMessage();}

    login($login_column_value, $password, $remember =

    false)The login method logs the user in.

    Parameters

    Param Type Default Description

    $login_column_value string The users login ( email or username ).

    $password string The users password

    $remember bool false Whether the remember me cookie should becreated or not.

    Returns Bool

    Throws SentryAuthException

  • Examples:

    // try to log a user intry{ // log the user in $valid_login = Sentry::login('[email protected]', 'secretpassword', true);

    if ($valid_login) { // the user is now logged in - do your own logic } else { // could not log the user in - do your bad login logic }

    }catch (SentryAuthException $e){ // issue logging in via Sentry - lets catch the sentry error thrown // store/set and display caught exceptions such as a suspended user with limit attempts feature. $errors = $e->getMessage();}

  • force_login($id, $provider = 'Sentry-Forced')

    Forces a login. A user will be logged in as long as that user exists.

    Paramaters

    Param Type Default Description

    $id int|string The user id or loing ( email or username )

    $provider string Sentry-Forced What system was used to force the login

    Returns True

    Throws SentryAuthException

    Examples:

    // basic force_login exampletry{ // force login Sentry::force_login('[email protected]');}catch (SentryAuthException $e){ // could not for the login - user not found

  • $error = $e->getMessage();}

    logout()

    The logout method logs the user out and destroys all Sentry sessions/cookies for the user.

    Returns void

    Examples:

    // log the user outSentry::logout();

    check()

    The check methods returns a bool of whether the user is logged in or not

    Returns bool

    Examples:

  • // basic login check exampleif (Sentry::check()){ // the user is logged in}else{ // the user is not logged in}

    // user needs to be logged in to view page exampleif ( ! Sentry::check()){ // redirect to login}

    activate_user($login_column_value, $code, $encoded

    = true)The activate_user method activates a non-active user.

    Parameters

    Param Type Default Description

    $login_column_value string The users login ( email or username ).

    $code string The users activation hash.

  • $decode bool true If the login value needs to be decoded.

    Returns Bool|Array ( user Array )

    Throws SentryAuthException

    Examples:

    // try to log a user intry{ // log the user in $activate_user = Sentry::activate_user('VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==', '93kavFY63S8jtala93a76fQ...'); // or $activate_user = Sentry::activate_user('[email protected]', '93kavFY63S8jtala93a76fQ...', false);

    if ($activate_user) { // the user is now activated - do your own logic } else { // user was not activated }

  • }catch (SentryAuthException $e){ // issue activating the user // store/set and display caught exceptions such as a suspended user with limit attempts feature. $errors = $e->getMessage();}

    reset_password($login_column_value, $password)

    The reset_password method returns an array or false. The new password and reset hash will be stored intemporary fields in the database.

    Parameters

    Param Type Default Description

    $login_column_value string The users login.

    $password string A new password that the user wants to use.

    Returns Bool|Array

    Throws SentryAuthException

  • Notes: The new password will not come into effect until confirmed. Also, if a user logs

    into the account before the password is confirmed, the entire reset password process will

    be nullified.

    Examples:

    try{ // reset the password $reset = Sentry::reset_password('[email protected]', 'newpassword');

    if ($reset) { $email = $reset['email']; $link = 'domain.com/auth/reset_password_confirm/'.$reset['link']; // adjust path as needed

    // email $link to $email } else { // password was not reset }

    }catch (SentryAuthException $e){

  • // issue activating the user // store/set and display caught exceptions such as a user not existing or user is disabled $errors = $e->getMessage();}

    reset_password_confirm($login_column_value,

    $code, $decode = true)The reset_password_confirm method returns a boolean if the reset password has been confirmed or not. Ifit is confirmed, the passwords are updated in the database appropriately.

    Parameters

    Param Type Default Description

    $login_column_value string The users login.

    $code string The password reset hash.

    $decode bool true If the login value needs to be decoded.

    Returns Bool

    Throws SentryAuthException

  • Notes: If the user logs in to their account before confirming the reset, the reset process

    will be nullified.

    Examples:

    try{ // confirm password reset $confirm_reset = Sentry::reset_password_confirm('VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==', '93kavFY63S8jtala93a76fQ...'); // or $confirm_reset = Sentry::reset_password_confirm('[email protected]', '93kavFY63S8jtala93a76fQ...', true);

    if ($confirm_reset) { // show success page or redirect to login - or whatever you want } else { // password was not reset - bad login/hash combo }

    }catch (SentryAuthException $e)

  • { // issue activating the user // store/set and display caught exceptions such as a user not existing or user is disabled $errors = $e->getMessage();}

    Users create()

    register()

    update()

    delete()

    enable()

    disable()

    user_exists()

    get()

    all()

    change_password()

  • groups()

    add_to_group()

    remove_from_group()

    in_group()

    is_admin()

    has_level()

    atleast_level()

    create(array $user, $activation = false)

    The create method creates a user

    Parameters

    Param Type Default Description

    $user arrayAn array consisting of the 'username', 'email', and'password' and their values. If 'email' is the login column,'username' is not required.

    $activation bool false If set to true, the user is required to activate their accountbefore they can log in.

  • Returns Integer|Array - user_id, or an array of user_id and activation hash.

    Throws SentryUserException

    Notes: The create method checks to make sure the login and emails are unique. Create is

    typically used for admin user creation.

    Examples:

    try{ // create the user - no activation required $vars = array( 'email' => '[email protected]', 'password' => 'mypass', 'metadata' => array( 'first_name' => 'John', 'last_name' => 'Doe', // add any other fields you want in your metadata here. ( must add to db table first ) ) );

    $user_id = Sentry::user()->create($vars);

  • if ($user_id) { // the user was created - send email notifying user account was created } else { // something went wrong - shouldn't really happen }}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user exists or bad fields}

    register(array $user)

    The register method creates a user. It is just an alias for the create method with activation set to true.

    Parameters

    Param Type Default Description

    $user arrayAn array consisting of the 'username', 'email', and 'password'and their values. If 'email' is the login column, 'username' is notrequired.

    Returns Integer|Array - user_id, or an array of user_id and activation hash.

  • Throws SentryUserException

    Notes: The register method checks to make sure the login and emails are unique.

    Register is typically used for the user registration process unless you do not want

    activation.

    Examples:

    try{ // create the user $user = Sentry::user()->register(array( 'email' => '[email protected]', 'password' => 'mypass', 'metadata' => array( 'first_name' => 'John', 'last_name' => 'Doe', // add any other fields you want in your metadata here. ( must add to db table first ) ) ));

    if ($user) { // the user was created

  • $link = 'domain.com/auth/activate/'.$user['hash'];

    // send email with link to activate. } else { // something went wrong - shouldn't really happen }}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user exists or bad fields}

    update(array $fields, $hash_password = true)

    The update method can be used to update any field in the 'users' or 'users_metadata' tables for a user.

    Parameters

    Param Type Default Description

    $fields array An array consisting of fields to update. Metadatafields will need to be an array within a metadata key.

    $hash_password bool true If set to true, all password fields will be hashed.

    Returns Bool

  • Throws SentryUserException

    Notes: The register method checks to make sure the login and emails are unique.

    Register is typically used for the user registration process unless you do not want

    activation.

    Examples:

    try{ // update the user $user = Sentry::user(25); $update = $user->update(array( 'password' => 'somenewpassword', 'metadata' => array( 'first_name' => 'John', 'last_name' => 'Doe' ) ));

    if ($update) { // the user was updated } else

  • { // something went wrong }}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user not existing or bad fields}

    delete()

    The delete method deletes a user.

    Returns Bool

    Throws SentryUserException

    Examples:

    try{ // update the user $user = Sentry::user(25); $delete = $user->delete();

    if ($delete)

  • { // the user was deleted } else { // something went wrong }}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user not existing}

    enable()

    Enables a user.

    Returns Bool

    Throws SentryUserException

    Examples:

    try{ $enabled = Sentry::user(25)->enable();

  • if ($enabled) { // user was enabled } else { // something went wrong }}catch (\SentryUserException $e){ $errors = $e->getMessage();}

    disable()

    Disables a user.

    Returns Bool

    Throws SentryUserException

    Examples:

    try{

  • $disabled = Sentry::user(25)->disable(); if ($disabled) { // user was disabled } else { // something went wrong }}catch (\SentryUserException $e){ $errors = $e->getMessage();}

    user_exists($login_column_value)

    The user_exists methods returns a bool of whether the user exists or not.

    Parameters

    Param Type Default Description

    $login_column_value int|string The user_id or users login.

    Returns Bool

  • Notes: This is just a helper function. You do not need to add this check in on registration

    or user creation. These methods already check to make sure the user is unique by calling

    user_exists.

    Examples:

    if (Sentry::user_exists('[email protected]')){ // the user exists}else{ // the user does not exist}

    get($field = null)

    The get method returns requested fields.

    Parameters

    Param Type Default Description

    $field string|arrayA field or array of fields to return from the 'users' table. To

  • retrieve metadata use 'metadata'.

    Returns mixed

    Throws SentryUserException

    Notes: FuelPHP's array '.' notation works with retrieving data from arrays.

    Examples:

    try{ // select the user $user = Sentry::user(25);

    // option 1 $email = $user->get('email'); $metadata = $user->get('metadata');

    // option 2 $user_data = $user->get(array('email', 'metadata'));

    // option 3 $first_name = $user->get('metadata.first_name');}

  • catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user not existing or bad fields}

    all()

    The all method retrives all users

    Returns Array

    // get all users$users = Sentry::user()->all();

    change_password($password, $old_password)

    The change_password method updates the users password. Their old password is required as well.

    Parameters

    Param Type Default Description

    $password string The users new password

    $old_password string The users old password

  • Returns bool

    Throws SentryUserException

    Examples:

    try{ // update the user $user = Sentry::user(25);

    if ($user->change_password('newpassword', 'oldpassword')) { // password has been updated } else { // something went wrong }}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as incorrect old password}

  • groups()

    Returns an array of groups the user is part of.

    Returns Array

    Examples:

    try{ // update the user $user = Sentry::user(25); $user_groups = $user->groups();}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user doesn't exist}

    add_to_group($id)

    Adds the user to a group.

  • Parameters

    Param Type Default Description

    $id int|string The groups id or name

    Returns Bool

    Throws SentryUserException

    Examples:

    try{ // update the user $user = Sentry::user(25);

    // option 1 $user->add_to_group(2);

    // option 2 $user->add_to_group('editor');}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user already in group}

  • remove_from_group($id)

    Removes a user from a group.

    Parameters

    Param Type Default Description

    $id int|string The groups id or name

    Returns Bool

    Throws SentryUserException

    Examples:

    try{ // update the user $user = Sentry::user(25);

    // option 1 $user->remove_from_group(2);

    // option 2

  • $user->remove_from_group('editor');}catch (SentryUserException $e){ $errors = $e->getMessage(); // catch errors such as user already not in group.}

    in_group($name)

    Checks to see if the user is in a group

    Parameters

    Param Type Default Description

    $name int|string The groups id or name

    Returns Bool

    Examples:

    // check to see if the current user is in the editors(id:2) groupif (Sentry::user()->in_group(2)) // or in_group('editors');{ // user is in the group

  • }else{ // user is not in the group}

    is_admin()

    Checks to see if the user is an admin

    Returns Bool

    Examples:

    // check to see if the current user is an adminif (Sentry::user()->is_admin()){ // user is an admin}else{ // user is not an admin}

  • has_level($level)

    Checks to see if the user contains a certain level

    Parameters

    Param Type Default Description

    $level int The level number.

    Returns Bool

    Examples:

    // check to see if the current user has a user level equal to 10if (Sentry::user()->has_level(10)){ // user contains a level equal to 10}else{ // user does not contain a level equal to 10}

  • atleast_level($level)

    Checks to see if the user contains a certain level

    Parameters

    Param Type Default Description

    $level int The level number.

    Returns Bool

    Examples:

    // check to see if the current user has a user level of 10 or higherif (Sentry::user()->atleast_level(10)){ // user has a level of 10 or higher}else{ // user does not have a level of at least 10}

  • Groups group()

    create()

    update()

    delete()

    users()

    all()

    group_exists()

    group($id = null)

    The group method grabs and sets all group information. It does not return anything.

    Parameters

    Param Type Default Description

    $id int|string null The group id or name.

  • Returns Sentry_Group

    Throws SentryGroupException

    Examples:

    // set the grouptry{ $group = Sentry::group(25); // or $group = Sentry::group('somegroup'); //or $group = Sentry::group();}catch (SentryGroupException $e){ $errors = $e->getMessage();}

    create($group)

    The create method creates a new group.

  • Parameters

    Param Type Default Description

    $group arrayAn array of consisting of the groups 'name' and 'level'. Optionalfields are 'is_admin' and 'parent'. The group name must beunique.

    Returns Bool|Int ( false or group id )

    Throws SentryGroupException

    Examples:

    // create a grouptry{ $group_id = Sentry::group()->create(array( 'name' => 'myadmin', 'level' => 100, ));}catch (SentryGroupException $e){ $errors = $e->getMessage();}

  • update(array $fields)

    The update method updates the current group.

    Parameters

    Param Type Default Description

    $fields array Array of fields to update for the group.

    Returns Bool

    Throws SentryGroupException

    Examples:

    // update a grouptry{ $group = Sentry::group(4); $update = $group->update(array( 'name' => 'New Name', 'level' => 100, ));

    if ($update)

  • { // group was updated } else { // group was not updated }}catch (SentryGroupException $e){ $errors = $e->getMessage();}

    delete()

    The delete method deletes the current group and all associations to it.

    Returns Bool

    Throws SentryGroupException

    try{ if (Sentry::group(4)->delete()) {

  • // group was deleted } else { // group was not deleted }}catch (SentryGroupException $e){ $errors = $e->getMessage();}

    get($field = null)

    The get method gets a given field (or array of fields).

    Parameters

    Param Type Default Description

    $field string null The name of field.

    Returns String value or Array of values

    Throws SentryGroupException

  • Examples:

    // get group informationtry{ $group_level = Sentry::group(2)->get('level'); //or $group_info = Sentry::group(2)->get(array('name', 'level')); //or $group_info = Sentry::group(2)->get();}catch (SentryGroupException $e){ $errors = $e->getMessage();}

    users()

    The users method returns all the users in the group.

    Returns Array

    Examples:

  • // get group informationtry{ $users = Sentry::group(2)->users();}catch (SentryGroupException $e){ $errors = $e->getMessage();}

    all()

    The all method returns all groups

    Returns Array

    Examples:

    // get group informationtry{ $groups = Sentry::group()->all();}catch (SentryGroupException $e)

  • { $errors = $e->getMessage();}

    group_exists($name)

    The group_exists methods returns a bool of whether the group exists or not.

    Parameters

    Param Type Default Description

    $name int|string The groups id or name.

    Returns Bool

    Notes: This is just a helper function. You do not need to add this check in on group

    creation creation. Create already checks if the name already exists or not.

    Examples:

    // check if group existsif (Sentry::group_exists('mygroup')) // or Sentry::group_exists(3)

  • { // the group exists}else{ // the group does not exist}

    Security attempts()

    get_limit()

    get()

    add()

    clear()

    suspend()

  • attempts($login_id = null, $ip_address = null)

    The attempts method sets and returns a Sentry_Attempts object.

    Parameters

    Param Type Default Description

    $login_id string null The users login.

    $ip_address string null The users ip address

    Returns Sentry_Attempts

    Throws SentryAttemptsException

    Notes: The exceptions with this method are only thrown if there are bad config settings.

    You should only have to worry about them during the inital setup of Sentry.

    Examples:

    // get the Sentry_Attempts object// sets attempts data for all users$attempts = Sentry::attempts();

  • // sets attempts data for a user$attempts = Sentry::attempts('[email protected]');

    // set attempts data for an ip address$attempts = Sentry::attempts(null, '123.432.2.1');

    // set attempts for a single user/ip combo$attempts = Sentry::attempts('[email protected]', '123.432.2.1');

    get_limit()

    The get_limit method returns the number of attempts allowed before a user is suspended.

    Returns Integer

    Examples:

    // get attempt limit$attempts = Sentry::attempts()->get_limit(); // returns int

    Notes: Use an existing object if one is available to prevent extra queries. The result will

  • be the same on all objects as it is just pulling from the config.

    get()

    The get method returns the number of failed attempts a login / ip combo has tried.

    Returns Integer|Array - number of failed attempts, array of associated login/ip attempts

    Examples:

    // get attempts

    // for all cases$attempts = Sentry::attempts()->get(); // returns array

    // for a single case$attempts = Sentry::attempts('[email protected]', '123.432.2.1')->get(); // returns int

    // for all attempts associated to a username or ip$attempts = Sentry::attempts('[email protected]')->get(); // returns array$attempts = Sentry::attempts(null, '123.432.2.1')->get(); // returns array

  • add()

    The add method adds an attempt to a certain login/ip combo.

    Throws SentryAttemptsException

    Examples:

    // add an attempttry{ Sentry::attempts('[email protected]', '123.432.2.1')->add(); // works fine

    Sentry::attempts()->add(); // this or any other combo will throw an exception - login/ip required}catch (SentryAttemptsException $e){ $error = $e->getMessage();}

    clear()

    The clear method removes attempts and suspensions for all, or the selected, users

  • Notes: If you have multiple Sentry_Objects, the attempts won't be updated when cleared

    unless you refresh that instance.

    Examples:

    // clear attempts for all usersSentry::attempts()->clear();

    // clear all attempts for login idSentry::attempts('[email protected]')->clear();

    // clear all attempts for an ipSentry::attempts(null, '123.432.21.1')->clear();

    // clear all attempts for a login/ip comboSentry::attempts('[email protected]', '123.432.2.1')->clear();

    suspend()

    The suspend method suspends a login/ip combo for a set amount of time.

    Throws SentryAttemptsException

  • Examples:

    // suspend a usertry{ Sentry::attempts('[email protected]', '123.432.2.1')->suspend(); // works fine

    Sentry::attempts()->suspend(); // this or any other combo will throw an exception - login/ip required}catch (SentryAttemptsException $e){ $error = $e->getMessage();}

    Sentry Social ( add-on )Sentry Social is an add-on to Sentry that allows you to easily create and log users into Sentry'sauthentication system via social networking sites that support OAuth or OAuth2. Dependencies: Fuel OAuth and OAuth2 packages.

  • FeaturesSimple Social Integration with Sentry

    Automatically creates Sentry Users

    Supports OAuth and OAuth2

    Utilizes the OAuth and OAuth2 fuel packages

    DownloadComing Soon

  • InstallationOnce downloaded, add the sentrysocial folder to the 'fuel/packages' directory. Installing thesocial_authorization table is as simple as running an oil migration.

    Notes: Your database connection needs to be setup first. The DB_Util code can be found

    in sentrysocial/migrations if you can not install via oil for some reason.

    $ php oil r migrate --packages=sentrysocial

    Configuration Callback Url

    Providers

  • Callback Url

    Option Type Default Description

    callback_url string null The Url your callback logic is located in

    Providers

    Option Type Default Description

    app_id string null Your App Id for the provider.

    app_secret string null Your App Secret for the provider.

    driver string null What driver/protocol to use for the provider. ( OAuth or OAuth2 )

    Notes: Provider support dependent on OAuth and OAuth2 packages.

    Examples:

    // example config

  • return array(

    /** * Callback URL */ 'callback_url' => 'www.mysite.com/auth/callback',

    /** * Social Providers */ 'providers' => array(

    'facebook' => array( 'app_id' => 'your app id', 'app_secret' => 'your app secret', 'driver' => 'OAuth2' ),

    'twitter' => array( 'app_id' => 'your app id', 'app_secret' => 'your app secret', 'driver' => 'OAuth' ),

    ));

  • UsageSentry Social is simple to use in any controller. All you need is 2 methods, one to authenticate and one toprocess the callback.

    Notes: Since not all providers allow you to retrieve an email address ( such as twitter ),

    when a user is created we give them a default email address of (uid)@(provider).user. If

    you require a real e-mail address, you can do a check for '@provider.user' and prompt

    the user to update with a legitimate email address.

    Notes: Upon user creation, a random string is created for a default password. This

    password is not sent anywhere. A user can also log in through sentry in the future since

    SentrySocial creates a real user.

    Examples:

    // Example Controller

    class Controller_Oauth extends Controller

  • { /** * Authenticate the user */ public function action_authenticate() { // replace 'facebook' with any other provider in your config SentrySocial::forge('facebook')->authenticate(); }

    /** * Callback * * @param string provider */ public function action_callback($provider) { if (SentrySocial::forge($provider)->login()) { // redirect your user - successful login // user is also created if it didn't exist Response::redirect('some/page'); } else { // authentication failed.. redirect back to login page Response::redirect('login/page'); } }}

  • Cartalyst | Support | LicenceAll That Serious Mumbo Jumbo - 2012 Cartalyst LLC - All Rights Reserved.