HowTo: Integrate GotoMeeting for Authentication and Provisioning
Goal
This article will guide you through the process how to setup your GotoMeeting Tenant and accordingly configure MyWorkspace to let Users login with their personal Account into GotoMeeting but also ensure a user is equipped with the right license (equals provisioning and de-provisioning).
Since GotoMeeting is part of LogMeIn we nevertheless refer to GotoMeeting in this article.
Validate Domain in LogMeIn Admin Portal
To let users login with MyWorkspace to GotoMeeting you need to verify the ownership of the corresponding domain a user belongs to. Please follow this guide: https://support.goto.com/training/help/set-up-domains-g2t710101
Add GotoMeeting App in MyWorkspace
- Go to MyWorkspace Admin Section, go to Applications, click on the Plus-Button and start creating a new GotoMeeting App
- Give a representative Name and Description to the App
- Create on app for Pro License Assignment and
- another app for Standard License Assignment
- Activate "Enable automatic account provisioning" to setup provisioning
- You will be prompted a LogMeIn Login Page. Please sign in with an Admin User
- Your License Options will be displayed after successful login with an Admin User
- Click "Save" to save the current settings
Configure SSO in LogMeIn Admin Portal
- Stay in the app configuration and go to Integration Guide Tab
- Follow the steps described there to configure SSO for your LogMeIn Tenant
Create Provisioning Workflow in MyWorkspace
- Go to MyWorkspace Admin Section, go to Workflows, click on the Plus-Button and start creating a new Workflow for Provisioning
- Give the Workflow a spelling name (you need to find and assign the WF later to the previously created app) and click create. You will see an editor with no content.
- Add the following script to the Workflow Editor
Note: This feature is only applicable for Enterprise Edition Customers with Preview enabled
// get necessary values from context // parse the protocol configuration, because it is a escaped string let oauth2ProtocolConfiguration = JSON.parse(context.OAuth2ProtocolConfiguration); let accountKey = oauth2ProtocolConfiguration.account_key; let accessToken = oauth2ProtocolConfiguration.access_token; let provisionedUser = context.ProvisionedUser; let licenseKeysAsArray = context.Application.ApplicationSettings.Fields.ApplicationLicenses; let accountProvisioningEnabled = context.Application.ApplicationSettings.Fields.EnableAccountProvisioning; // helper functions let hasSingleResult = function (httpResponseFromServiceProvider) { return (httpResponseFromServiceProvider && httpResponseFromServiceProvider.fromIndex === 0 && httpResponseFromServiceProvider.toIndex === 1 && httpResponseFromServiceProvider.total === 1); }; let hasNoResult = function (httpResponseFromServiceProvider) { return (httpResponseFromServiceProvider && httpResponseFromServiceProvider.fromIndex === 0 && httpResponseFromServiceProvider.toIndex === 0 && httpResponseFromServiceProvider.total === 0); }; let hasKeys = function (licenseKeysAsArray) { return (licenseKeysAsArray && licenseKeysAsArray.length > 0); }; let isEmpty = function (userKey) { return (!userKey || 0 === userKey.length); }; // inject the raw response into the context let handleOnComplete = function () { done(context); }; // if the user exists in GTM we just assign him the licenses let assignLicensesToUser = function (licensesKeysAsString, userKey) { rest.post('https://api.getgo.com/admin/rest/v1/accounts/' + accountKey + '/licenses/' + licensesKeysAsString + '/users/' + userKey, { headers: { 'Accept': 'application/json', 'Content-type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }).on('complete', function (data, response) { handleOnComplete(); }); }; // if the user does not exist in GTM we create him and assign the licenses let createUserInGtmAndAssignLicenses = function () { rest.post('https://api.getgo.com/admin/rest/v1/accounts/' + accountKey + '/users', { headers: { 'Accept': 'application/json', 'Content-type': 'application/json', 'Authorization': 'Bearer ' + accessToken }, data: JSON.stringify({ users: [{ email: provisionedUser.MailAddress, firstName: provisionedUser.FirstName, lastName: provisionedUser.LastName, locale: "en_US" } ], licenseKeys: licenseKeysAsArray, emailContent: { subject: "Welcome to GoToMeeting Admin APIs", text: "You have been added as a user to the Citrix GoToMeeting Admin APIs. Log in using your email as User ID at developer.citrixonline.com." } }) }).on('complete', function (data, response) { handleOnComplete(); }); }; // try to get the user from GTM let getUserFromGotoMeeting = function () { return rest.get('https://api.getgo.com/admin/rest/v1/accounts/' + accountKey + '/users?filter=(email="' + provisionedUser.MailAddress + '")', { headers: { 'Accept': 'application/json', 'Content-type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }); }; // logic to do the provisioning let executeWorkflow = function () { // get the user getUserFromGotoMeeting().on('complete', function (getUserFromGoToMeetingResponse) { let callHandleOnComplete = true; // if no result, create user if (hasNoResult(getUserFromGoToMeetingResponse)) { callHandleOnComplete = false; createUserInGtmAndAssignLicenses(); // if single result, set licenses } else if (hasSingleResult(getUserFromGoToMeetingResponse)) { let userKey = getUserFromGoToMeetingResponse.results[0].key; // if there is a user key and licenses procees, otherwise do nothing if (hasKeys(licenseKeysAsArray) && !isEmpty(userKey)) { callHandleOnComplete = false; let licenseKeysAsString = licenseKeysAsArray.join(); assignLicensesToUser(licenseKeysAsString, userKey); } } if(callHandleOnComplete) { handleOnComplete(); } } ); }; // check if account provisioning is enabled if(accountProvisioningEnabled === true) { // execute the provisioning workflow executeWorkflow(); } else { handleOnComplete(); }
-
The script is now added to the editor. Please save the Workflow (Disk-Icon on the top right)
-
You see the list of all Workflows and your created Workflow is listed
Create De-Provisioning Workflow in MyWorkspace
Note: This feature is only applicaple for Enterprise Edition Customers with Preview enabled
- Go to MyWorkspace Admin Section, go to Workflows, click on the Plus-Button and start creating a new Workflow for De-Provisioning
- Give the Workflow a spelling name (you need to find and assign the WF later to the previously created app) and click create. You will see an editor with no content.
- Add the following script to the Workflow Editor and click save (Disk-Icon on the top right)
// get necessary values from context // parse the protocol configuration, because it is a escaped string let oauth2ProtocolConfiguration = JSON.parse(context.OAuth2ProtocolConfiguration); let accountKey = oauth2ProtocolConfiguration.account_key; let accessToken = oauth2ProtocolConfiguration.access_token; let provisionedUser = context.ProvisionedUser; let accountProvisioningEnabled = context.Application.ApplicationSettings.Fields.EnableAccountProvisioning; // helper functions let hasSingleResult = function (httpResponseFromServiceProvider) { return (httpResponseFromServiceProvider && httpResponseFromServiceProvider.fromIndex === 0 && httpResponseFromServiceProvider.toIndex === 1 && httpResponseFromServiceProvider.total === 1); }; let isEmpty = function (userKey) { return (!userKey || 0 === userKey.length); }; // inject the raw response into the context let handleOnComplete = function () { done(context); }; // try to get the user from GTM let getUserFromGotoMeeting = function () { return rest.get('https://api.getgo.com/admin/rest/v1/accounts/' + accountKey + '/users?filter=(email="' + provisionedUser.MailAddress + '")', { headers: { 'Accept': 'application/json', 'Content-type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }); }; // try to delete the user from GTM let deleteUserFromGotoMeeting = function (userKey) { rest.del('https://api.getgo.com/admin/rest/v1/accounts/' + accountKey + '/users/' + userKey, { headers: { 'Accept': 'application/json', 'Content-type': 'application/json', 'Authorization': 'Bearer ' + accessToken } }).on('complete', function (data, response) { handleOnComplete(); } ); }; // logic to do the provisioning let executeWorkflow = function () { // get the user getUserFromGotoMeeting().on('complete', function (getUserFromGoToMeetingResponse) { let callHandleOnComplete = true; // if a single user is found, try to delete it if (hasSingleResult(getUserFromGoToMeetingResponse)) { // get the user key let userKey = getUserFromGoToMeetingResponse.results[0].key; // if its not empty, delete it if (!isEmpty(userKey)) { callHandleOnComplete = false; deleteUserFromGotoMeeting(userKey); } } if(callHandleOnComplete) { handleOnComplete(); } } ); }; // check if account provisioning is enabled if(accountProvisioningEnabled === true) { // execute the provisioning workflow executeWorkflow(); } else { handleOnComplete(); }
Assign Provisioning and De-Provisioning Workflow to GotoMeeting App
- Go to MyWorkspace Admin Section, go to Applications and edit the previously created GotoMeeting App
Note: do this for every GotoMeeting App created - Goto Workflows in the App configuration
- Choose the previously created Provisioning Workflow and select it for "User assigned to Application". This ensure users get provisioning for GotoMeeting once they got granted access rights to the app
- Do the same for De-Provisioning. Choose the previously created De-Provisioning Workflow and select it for "User unassigned to Application". This ensure users get de-provisioned for GotoMeeting once access rights to the app are revoked
- Click "Save" to save the current settings
What's Next
This is what was achieved and what was omitted in this how-to.