Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

In progress

This paper is currently in the process of being written.

1) Summary

The goal of this paper is to provide tips and good practices on how to perform a multi-tenant integration with Maestrano, i.e be able to handle multiple Maestrano-powered marketplaces including Maestrano.com.

The Maestrano delivery network is essentially composed of two types of marketplaces:

  • Enterprise Network: these enterprise tenants run the Maestrano infrastructure in their private cloud. In order to publish your application to these tenants' marketplace you will need to 1) have an agreement with them (which we can facilitate) and 2) add a configuration manifest to your application allowing you to "discover" their API endpoints.
  • Express Network: these tenants run their own marketplace using the Marketplace as a Service (MaaS) offering, powered by Maestrano's cloud. Being an app provider on maestrano.com makes you automatically available on these marketplaces - meaning you do not need to do anything on your side. Please note that the marketplace owners may choose to restrict their offering to a limited number of apps.

The diagram below provides a general overview of the Maestrano Enterprise Delivery Network:

 

2) Principles

When doing multi-tenant integrations, three concept need to be scoped: Configuration, URLs and Records.

Configuration scoping

Which configuration parameters should be used based on the context (url, field stored in database)? Maestrano.com has its own set of API endpoints but other enterprise tenants will have other different ones.

URL scoping

One way of understanding the context is to properly scope urls. E.g.: Webhooks coming from Maestrano should hit a url like "/maestrano/some-webhook" while webhooks coming from another tenant should look like "/sometenant/some-webhook". In a more general manner, URLs related to Maestrano integration should be parameterized using a tenant key: "/:tenant_key/some-webhook"

Record scoping

When storing records related to Maestrano and/or one of Maestrano enterprise customers, then your application should be able to record to which tenant it is related to. This is usually done by storing a tenant key on the record or in an identity lookup table.

 

3) Example of multi-tenant implementation (pseudo code)

The example below gives a high level overview of what your code may look like in the context of a multi-tenant integration. If you have already done the integration to maestrano.com, the code below will look familiar and essentially intends to show how you can "extend" your current integration to make it multi-tenant.

This code samples show you the general steps involved in getting a basic multi-tenant setup for Single Sign-On, Single Billing and Connec data sharing. For this example, we assume the use of one of Maestrano's SDKs - available in Ruby, Java, PHP and .NET.

a) Configuration

The configuration step involves declaring multiple tenant configurations, parameterizing the routes that will be used by our controllers (SSO, Connec etc.) and adding a metadata endpoint to expose our tenant specific configuration.

App Initializer
# This piece of code should be put in an initializer. 
# 
# With the Maestrano SDKs, you have the ability to add as many 
# marketplace configurations as you want. E.g.: you can add a configuration manifest
# for 'maestrano' and another one for 'acme-corp'.
#
# These configuration manifests only need to be added for Enterprise Tenants, which host a dedicated
# Maestrano infrastructure on their private cloud.
 
#
# Create a configuration manifest for the key "maestrano"
#
Maestrano.with("acme-corp").configure({
    # Tenant specific configuration
    sso_idp: "https://maestrano.com",
    account_api_host: "https://maestrano.com",
	connec_api_host: "https://api-connec.maestrano.com",
    
    # My app configuration for this tenant - note the use of the tenant key
    # in the url.
    # This URL will be used by Maestrano.com to send you notifications
    app_webhook_path: "https://myapp.com/mno-enterprise/maestrano/connec/receive"
})
 
#
# Create a configuration manifest for the key "acme-corp"
#
Maestrano.with("acme-corp").configure({
    # Tenant specific configuration
    sso_idp: "https://saml.acme-corp.com",
    account_api_host: "https://accounts.acme-corp.com",
	connec_api_host: "https://api-connec.acme-corp.com",
    
    # My app configuration for this tenant - note the use of the tenant key
    # in the url.
    # This URL will be used by Acme Corp to send you notifications
    app_webhook_path: "https://myapp.com/mno-enterprise/acme-corp/connec/receive"
})
App Routes
# Let's create parameterized routes

# The single sign-on routes will be used by enterprise tenants to 
route "/mno-enterprise/:tenant_key/saml/initialize" to "SamlSSoController"
route "/mno-enterprise/:tenant_key/saml/consume" to "SamlSSoController"
 
# The metadata route will be fetched by the enterprise tenants to retrieve your configuration
route "/mno-enterprise/:tenant_key/metadata" to "MetadataController"
 
# The Connec!™ webhook route will be used by enterprise tenants to POST data sharing notifications
route "/mno-enterpise/:tenant_key/connec-webhook" to "ConnecWebhookController"
 
MetadataController
# The metadata controller exposes my configuration to the requesting tenant
# Thanks to this metadata controller, the tenant will be able to discover my configuration
# and send webhook notifications to the right endpoint.
class MetadataController
  
  # The show action matches the following request
  # GET /mno-enterprise/:tenant_key/metadata
  def show
    # Because the URL was parameterized, we can retrieve the tenant key
    # from the URL parameters
    tenant_key = params['tenant_key']
 
    # Next step to make sure we authenticate the tenant. Authentication is
    # tenant specific
    unless Maestrano.with(tenant_key).authenticate(http_basic['login'],http_basic['password'])
      render json: "Unauthorized, code: '401'
    end     
    
    # Eventually, we render our configuration manifest for this specific tenant
    render json: Maestrano.with(tenant_key).to_metadata
  end
  
end

 

??) Connec Webhooks

 

ConnecWebhookController
# This controller processes any data sharing notifications sent by tenants via
# Connec!
# E.g.: I receive a new invoice from Connec!™ that was created in another application
class WebhookConnecController
  
  # The 'receive' controller action matches the following request
  # POST /mno-enterprise/acme-corp/connec/receive
  def receive
  	# Here again, because the URL was parameterized, we can retrieve the tenant key
    # from the URL parameters
    tenant_key = params['tenant_key']

    # Authenticate request as usual
    unless Maestrano.with(tenant_key).authenticate(http_basic['login'],http_basic['password'])
      render json: "Unauthorized, code: '401'
    end
    
    # Finally, process the request for a specific tenant
    MyConnecWrapperClass.process_invoice_updates(params['invoices'],tenant_key)
  end
  
end

 

 

 

 

 

 

 

 

 

 

 

 

 

  • No labels