Maestrano Logo

Maestrano Cloud Integration is currently in closed beta. Want to know more? Send us an email to [email protected].


  1. Getting Setup
  2. Getting Started
  3. Account Webhooks
  4. API

Getting Setup

To start the integration of your application with the Maestrano platform, you first need to register your application on our Developer Platform. You can find more information here Once your application is registered, you will be provided with API keys that are used to configure your application on the different marketplaces powered by Maestrano.

A rails demo application is also available: https://github.com/maestrano/demoapp-rails

Getting Started

maestrano-rails works with Rails 3.2 onwards. You can add it to your Gemfile with:

gem 'maestrano-rails'

Run bundle to install the gem as well as the maestrano ruby bindings (dependency)

bundle

After you install Maestrano and add it to your Gemfile, you need to run the generator:

rails generate maestrano:install

The generator will install an initializer which describes Maestrano's configuration options.

The generator also generates a SamlController for single sign-on that you will need to customize (see below) as well as the required routes.

When you are done, you can start maestrano-izing your user and group model using the generators.

User model

Assuming your user model is called 'User' you can run the following generator to prepare this model for single sign-on:

rails generate maestrano:user User

This generator will create a migration adding a :provider and :uid field to your user model. If you are already using multi-auth strategies (using omniauth for example) then you can just ignore and delete this migration.

Run the migration with:

bundle exec rake db:migrate

This generator also adds a configuration block to your user model which looks like this:

class User < ActiveRecord::Base
  # Enable Maestrano for this user
  maestrano_user_via :provider, :uid do |user,maestrano|
    user.name = maestrano.first_name
    user.surname = maestrano.last_name
    user.email = maestrano.email

    #user.country_alpha2 = maestrano.country
    #user.some_required_field = 'some-appropriate-default-value'
  end

  ...

end

This block is used to create a mapping between your user model fields and the attributes provided by Maestrano during the single sign-on handshake.

Group model

Because Maestrano works with businesses it expects your service to be able to manage groups of users. A group represents 1) a billing entity 2) a collaboration group. During the first single sign-on handshake both a user and a group should be created. Additional users logging in via the same group should then be added to this existing group (see controller setup below)

Assuming your group model is called 'Organization' you can run the following generator to prepare this model for single sign-on:

rails generate maestrano:group Organization

This generator will create a migration adding a :provider and :uid field to your group model.

Run the migration with:

bundle exec rake db:migrate

This generator also adds a configuration block to your group model which looks like this:

class Organization < ActiveRecord::Base
  maestrano_group_via :provider, :uid do |group,maestrano|
    group.name = maestrano.company_name || "Your Group"

    # group.principal_email = maestrano.email
    # group.city = maestrano.city
    # group.olson_tz = maestrano.timezone
    # group.country_alpha2 = maestrano.country
    # group.currency_code = maestrano.currency
    # group.some_required_field = 'some-appropriate-default-value'
  end

  ...

end

Controller setup

The last step of integrating single sign-on with Maestrano is to customize the consume action of the SamlController. This action represents the last step of single sign-on handshake and should handle user finding/creation, group finding/creation, user-group relationship and finally user sign in.

The controller is located here: app/controllers/maestrano/auth/saml_controller.rb

The sample belows shows one possible way of writing this controller action:

class Maestrano::Auth::SamlController < Maestrano::Rails::SamlBaseController

  #== POST '/maestrano/auth/saml/consume'
  # -
  # Assuming you have enabled maestrano on a user model
  # called 'User' and a group model called 'Organization'
  # the action could be written the following way
  def consume
    # 1)Find or create the user and the group
    # --
    # The class method 'find_or_create_for_maestrano' is provided
    # by the maestrano-rails gem on the model you have maestrano-ized.
    # The method uses the mapping defined in the model 'maestrano_*_via' 
    # block to create the resource if it does not exist
    # The 'user_auth_hash' and 'group_auth_hash' methods are provided
    # by the controller.
    # --
    user = User.find_or_create_for_maestrano(user_auth_hash)
    organization = Organization.find_or_create_for_maestrano(group_auth_hash)


    # 2) Add the user to the group if not already a member
    # --
    # The 'user_group_rel_hash' method is provided by the controller.
    # The role attribute provided by maestrano is one of the following: 
    # 'Member', 'Power User', 'Admin', 'Super Admin'
    # The 'member_of?' and 'add_member' methods are not provided by 
    # maestrano and are left to you to implement on your models
    # --
    unless user.member_of?(organization)
      organization.add_member(user,role: user_group_rel_hash[:role])
    end


    # Sign the user in and redirect to application root
    # --
    # The 'sign_in' method is not provided by maestrano but should already
    # be there if you are using an authentication framework like Devise
    # --
    (user)
    redirect_to root_path
  end
end

Account Webhooks

Single sign on has been setup into your app and Maestrano users are now able to use your service. Great! Wait what happens when a business (group) decides to stop using your service? Also what happens when a user gets removed from a business? Well the controllers generated under RAILS_ROOT/app/controllers/maestrano/account/ are typically for Maestrano to be able to notify you of such events.

Groups Controller (service cancellation)

Sad as it is a business might decide to stop using your service at some point. On Maestrano billing entities are represented by groups (used for collaboration & billing). So when a business decides to stop using your service we will issue a DELETE request to the webhook.account.groups_path endpoint (typically /maestrano/account/groups/:id).

Maestrano only uses this controller for service cancellation so there is no need to implement any other type of action - ie: GET, PUT/PATCH or POST. The use of other http verbs might come in the future to improve the communication between Maestrano and your service but as of now it is not required.

Below is an example of what your groups destroy action might look like:

class Maestrano::Account::GroupsController < Maestrano::Rails::WebHookController

  # DELETE /maestrano/account/groups/cld-1
  # Delete an entire group
  def destroy
    group_uid = params[:id]

    # Perform deletion steps here
    # --
    # If you need to perform a final checkout
    # then you can call Maestrano::Account::Bill.create({.. final checkout details ..})
    # --
    # If Maestrano.param('sso.creation_mode') is set to virtual
    # then you might want to delete/cancel/block all users under
    # that group
    # --
    # E.g:
    organization = Organization.find_by_provider_and_uid('maestrano',group_uid)

    amount_cents = organization.calculate_total_due_remaining
    Maestrano::Account::Bill.create({
      group_id: group_uid, 
      price_cents: amount_cents, 
      description: "Final Payout"
    })

    if Maestrano.param('sso.creation_mode') == 'virtual'
      organization.members.where(provider:'maestrano').each do |user|
      user.destroy
    end

    organization.destroy
    render json: {success: true}
  end
end

Group Users Controller (business member removal)

A business might decide at some point to revoke access to your services for one of its member. In such case we will issue a DELETE request to the webhook.account.group_users_path endpoint (typically /maestrano/account/groups/:group_id/users/:id).

Maestrano only uses this controller for user membership cancellation so there is no need to implement any other type of action - ie: GET, PUT/PATCH or POST. The use of other http verbs might come in the future to improve the communication between Maestrano and your service but as of now it is not required.

Below is an example of what your group users destroy action might look like:

class Maestrano::Account::GroupUsersController < Maestrano::Rails::WebHookController

  # DELETE /maestrano/account/groups/cld-1/users/usr-1
  # Remove a user from a group
  def destroy
    # Set the right uid based on Maestrano.param('sso.creation_mode')
    user_uid = Maestrano.mask_user(params[:id],params[:group_id]) 
    group_uid = params[:group_id]

    # Perform association deletion steps here
    # --
    # If Maestrano.param('sso.creation_mode') is set to virtual
    # then you might want to just delete/cancel/block the user
    #
    # E.g
    user = User.find_by_provider_and_uid('maestrano',user_uid)
    organization = Organization.find_by_provider_and_uid('maestrano',group_uid)

    if Maestrano.param('sso.creation_mode') == 'virtual'
      user.destroy
    else
      organization.remove_user(user)
      user.block_access! if user.reload.organizations.empty?
    end

    render json: {success: true}
  end
end

API

The maestrano-rails gem also provides bindings to its REST API allowing you to access, create, update or delete various entities under your account (e.g: billing).

Your can read the API documentation directly on the maestrano gem project page.

Support

This README is still in the process of being written and improved. As such it might not cover some of the questions you might have.

So if you have any question or need help integrating with us just let us know at [email protected]

License

MIT License. Copyright 2017 Maestrano Pty Ltd. https://maestrano.com

You are not granted rights or licenses to the trademarks of Maestrano.