Scripting

The Groove.id scripting interface allows you to set customized policies for signing in, permissions, users, accounts, and more.

The scripting interface allows you to customize the behavior of Groove.id to suite your needs. You write scripts in TypeScript. Groove.id runs the scripts you provide whenever an event occurs. Your script can reject, modify, or ignore the event as you see fit. Scripts have read-only access to objects in the Groove.id API. You must be an Administrator to create, edit, or view scripts.

To get started, navigate to Settings, then Scripts and click New to create a new script.

A simple script

The script created is a simple example, which ensures that each user has a FullName property specified.

class Users implements UserPlugin {
  Create(ctx: Context, user: User) {
    if (!user.Name.FullName) {
      throw new BadRequestException('user must have a name')
    }
    return null
  }
}

const plugin: GrooveidPlugin = {
  Users: new Users()
}
export default plugin

Let’s try it out. Check the Enabled box and press Save.

Then navigate to People > New and try to create a user with no name. You will see an error message, and the user will not be created.

Navigate back to the script and check the logs tab to see what happened. You should see an error message in the output.

Modifying the object

Perhaps instead of failing when a user doesn’t have a name, we want to make one up somehow. Let’s modify the script so it looks like this:

class Users implements UserPlugin {
  Create(ctx: Context, user: User) {
    if (!user.Name.FullName) {
      user.Name.FullName = 'Anonymous Coward'
      return user // return the user because we want to apply changes.
    }
    return null // indicates that we don't want to change the user.
  }
}

const plugin: GrooveidPlugin = {
  Users: new Users()
}
export default plugin

Try creating a nameless user again. This time it will work, and a user named Anonymous Coward will appear. You can also check the script log and note a successful invocation.

Reading other objects

If we did a lot of this, we’d have a lot of people all named Anonymous Coward, which isn’t super useful. Let’s say we want to name the anonymous users as “Anonymous Coward 2”, “Anonymous Coward 3,” etc. Update the script so it looks like this:

class Users implements UserPlugin {
  Create(ctx: Context, user: User) {
    if (user.Name.FullName) {
      return null
    }

    let name = 'Anonymous Coward'
    for (let counter = 1; counter < 100; counter++) {
      // Now we are using the global `data` to examine other objects in the system.
      let nameExists = false
      data.Users.List({}, (existingUser: User) => {
        if (existingUser.Name.FullName == name) {
          console.log(
            'a user named ' +
              name +
              ' already exists: ' +
              existingUser.Metadata.ID +
              ' name: ' +
              existingUser.Name.FullName
          )
          nameExists = true
        }
      })
      if (!nameExists) {
        user.Name.FullName = name
        return user
      }
      if (nameExists) {
        name = 'Anonymous Coward ' + counter
      }
    }

    throw new Error('There are already 100 Anonymous Cowards')
  }
}

const plugin: GrooveidPlugin = {
  Users: new Users()
}
export default plugin

Reference

Groove.id plugins are typescript modules that export a single default export of type GrooveidPlugin.

Globals

  • data - Data - an interface to read and list all objects stored by Groove.id.
  • console - provides a log method to emit messages which are captured in the script log.

Types

GrooveidPlugin

GrooveidPlugin is top-level interface implemented by all Groove.id scripts. A Groove.id script must have a single default export that is of type GrooveidPlugin.

  • Accounts - AccountPlugin - optional. Plugins can implement this interface to monitor or modify creating, deleting and updating Account objects.
  • AccountChanges AccountChangePlugin - optional. Plugins can implement this interface to monitor or modify creating, deleting and updating AccountChange objects.
  • Apps AppPlugin - optional. Plugins can implement this interface to monitor or modify creating, deleting and updating App objects.
  • Groups GroupPlugin - optional. Plugins can implement this interface to monitor or modify creating, deleting and updating Group objects.
  • Users UserPlugin - optional. Plugins can implement this interface to monitor or modify creating, deleting and updating User objects.
  • SSH SSHPlugin - optional. Plugins can implement this interface to modify how SSH keys and sessions are handled.
  • Lifecycle LifecyclePlugin - optional. Plugins can implement this interface to modify account lifecycle operations.

AccountPlugin

Plugins can implement this interface to monitor or modify creating, deleting and updating Account objects.

  • Create - optional

(ctx: Context, account: Account) => Account| null

Create is a function that is invoked when someone is creating an Account.

If you return null from this function, then the Account will be created as specified by the caller.

If you wish to modify the Account that will be created, then the function should return the modified account.

If the account should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Update - optional

(ctx: Context, oldAccount: Account, account: Account) => Account| null

Update is a function that is invoked when someone is updating an Account. The oldAccount parameter contains the previous value of the account. The account parameter contains the new value of the account.

If you return null from this function, then the Account will be created as specified by the caller.

If you wish to modify the Account, then the function should modify the Account and return the modified account.

If the account should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Delete - optional

(ctx: Context, oldAccount: Account) => void

Delete is invoked when someone is deleting an Account. The ‘oldAccount’ parameter is the Account that will be deleted.

If the account should not be deleted, throw an exception, e.g. UnauthorizedException.

AccountChangePlugin

Plugins can implement this interface to monitor or modify creating, deleting and updating AccountChange objects.

  • Create - optional

(ctx: Context, accountchange: AccountChange) => AccountChange| null

Create is a function that is invoked when someone is creating an AccountChange.

If you return null from this function, then the AccountChange will be created as specified by the caller.

If you wish to modify the AccountChange that will be created, then the function should return the modified accountchange.

If the account change should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Update - optional

(ctx: Context, oldAccountChange: AccountChange, accountchange: AccountChange) => AccountChange| null

Update is a function that is invoked when someone is updating an AccountChange. The oldAccountChange parameter contains the previous value of the account change. The accountchange parameter contains the new value of the account change.

If you return null from this function, then the AccountChange will be created as specified by the caller.

If you wish to modify the AccountChange, then the function should modify the AccountChange and return the modified accountchange.

If the account change should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Delete - optional

(ctx: Context, oldAccountChange: AccountChange) => void

Delete is invoked when someone is deleting an Account. The ‘oldAccount’ parameter is the AccountChange that will be deleted.

If the account change should not be deleted, throw an exception, e.g. UnauthorizedException.

AppPlugin

Plugins can implement this interface to monitor or modify creating, deleting and updating App objects.

  • Create - optional

(ctx: Context, app: App) => App| null

Create is a function that is invoked when someone is creating an App.

If you return null from this function, then the App will be created as specified by the caller.

If you wish to modify the App that will be created, then the function should return the modified app.

If the app should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Update - optional

(ctx: Context, oldApp: App, app: App) => App| null

Update is a function that is invoked when someone is updating an App. The oldApp parameter contains the previous value of the app. The app parameter contains the new value of the app.

If you return null from this function, then the App will be created as specified by the caller.

If you wish to modify the App, then the function should modify the App and return the modified app.

If the app should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Delete - optional

(ctx: Context, oldApp: App) => void

Delete is invoked when someone is deleting an App. The ‘oldApp’ parameter is the App that will be deleted.

If the app should not be deleted, throw an exception, e.g. UnauthorizedException.

GroupPlugin

Plugins can implement this interface to monitor or modify creating, deleting and updating Group objects.

  • Create - optional

(ctx: Context, group: Group) => Group| null

Create is a function that is invoked when someone is creating a Group.

If you return null from this function, then the Group will be created as specified by the caller.

If you wish to modify the Group that will be created, then the function should return the modified group.

If the group should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Update - optional

(ctx: Context, oldGroup: Group, group: Group) => Group| null

Update is a function that is invoked when someone is updating a Group. The oldGroup parameter contains the previous value of the group. The group parameter contains the new value of the group.

If you return null from this function, then the Group will be created as specified by the caller.

If you wish to modify the Group, then the function should modify the Group and return the modified group.

If the group should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Delete - optional

(ctx: Context, oldGroup: Group) => void

Delete is invoked when someone is deleting a Group. The ‘oldGroup’ parameter is the Group that will be deleted.

If the group should not be deleted, throw an exception, e.g. UnauthorizedException.

UserPlugin

Plugins can implement this interface to monitor or modify creating, deleting and updating User objects.

  • Create - optional

(ctx: Context, user: User) => User| null

Create is a function that is invoked when someone is creating a User.

If you return null from this function, then the User will be created as specified by the caller.

If you wish to modify the User that will be created, then the function should return the modified user.

If the user should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Update - optional

(ctx: Context, oldUser: User, user: User) => User| null

Update is a function that is invoked when someone is updating a User. The oldUser parameter contains the previous value of the user. The user parameter contains the new value of the user.

If you return null from this function, then the User will be created as specified by the caller.

If you wish to modify the User, then the function should modify the User and return the modified user.

If the user should not be created then the function should throw an exception, e.g. UnauthorizedException.

  • Delete - optional

(ctx: Context, oldUser: User) => void

Delete is invoked when someone is deleting a User. The ‘oldUser’ parameter is the User that will be deleted.

If the user should not be deleted, throw an exception, e.g. UnauthorizedException.

SSHPlugin

Plugins can implement this interface to modify how SSH keys and sessions are handled.

  • AuthorizedKeys - optional

(ctx: Context, user: User, account: Account, authorizedKeys: Array<string>) => Array<string> | undefined

AuthorizedKeys is used when determining which SSH keys should be assigned to the specified account. To modify the SSH keys, return a array. If the keys should not be modified, return undefined.

LifecyclePlugin

Plugins can implement this interface to modify how SSH keys and sessions are handled.

  • GetUserForAccount - optional

(ctx: Context, app: App, account: Account) => User | undefined

GetUserForAccount in invoked when an unknown account is discovered in an app. If this function returns an existing user, then the account is associated with the account. If you return a new User then that user is created and the account associated with it. If the function returns undefined, then the default mapping is applied.

Context

Context is the first argument passed to each of the interception functions. This class provides information about the user attempting the operation.

  • Tenant - Tenant
  • AuthorizedUser - User
  • IntegrityLevel - IntegrityLevel
  • Intent - IntegrityLevelChangeIntent (optional)

Data

Data is the type of the global data variable that describes other objects in the system.

  • Tenant - TenantData
  • Accounts - AccountsData
  • AccountChanges - AccountChangesData
  • Apps - AppsData
  • Groups - GroupsData
  • Users - UsersData

TenantData

TenantData is the type of the global object data.Tenant which provides access to the global Tenant object.

  • Get

(): Tenant

Fetch the Tenant with the specified object ID.

AccountsData

AccountsData is the type of the global object data.Accounts which provides access to Account objects.

  • Get

(id: string): Account

Fetch the Account with the specified object ID.

  • List

(opts: ListOptions, cb: (account: Account) => void): void

List invokes the caller-provided callback with each account that matches the filters specified in opts.

AccountChangesData

AccountChangesData is the type of the global object data.AccountChanges which provides access to AccountChange objects.

  • Get

(id: string): AccountChange

Fetch the AccountChange with the specified object ID.

  • List

(opts: ListOptions, cb: (accountChange: AccountChange) => void): void

List invokes the caller-provided callback with each account that matches the filters specified in opts.

AppsData

AppsData is the type of the global object data.Apps which provides access to App objects.

  • Get

(id: string): App

Fetch the App with the specified object ID.

  • List

(opts: ListOptions, cb: (app: App) => void): void

List invokes the caller-provided callback with each account that matches the filters specified in opts.

GroupsData

GroupsData is the type of the global object data.Groups which provides access to Group objects.

  • Get

(id: string): Group

Fetch the Group with the specified object ID.

  • List

(opts: ListOptions, cb: (group: Group) => void): void

List invokes the caller-provided callback with each account that matches the filters specified in opts.

UsersData

UsersData is the type of the global object data.Users which provides access to User objects.

  • Get

(id: string): User

Fetch the User with the specified object ID.

  • List - (opts: ListOptions, cb: (user: User) => void): void

Exceptions

The following exception classes may be used to signal certain rejection conditions. You are free to throw your own exceptions, but these may trigger specific behavior.

UnauthorizedException

UnauthorizedException should be thrown by functions when the authorization context lacks sufficient authorization to proceed.

  • message - string

ForbiddenException

ForbiddenException should be thrown by functions when the called is prohibited from taking the action requested.

  • message - string

BadRequestException

BadRequestException should be thrown by functions when the object modification is malformed, for example, if an email address doesn’t match a convention.

  • message - string

ListOptions

ListOptions is the type of the opts argument to the List methods for each data object. It specifies which objects to return.

  • Limit - number - the maximum number of items to return
  • Order - Array<string> - order the returned objects by the specified field names. Prefix a string with a dash to reverse the order.
  • Filter - Array<ListFilter> - filter objects to only those that match the filter expression. (Note: although the API implies that multiple filters may be specified, for most objects, only one filter expression is allowed. This may change in future versions of the interface.)

ListFilter

ListFilter specifies an object filter that can be applied.

  • Field - string - the name of the field. Nested fields can be specified by separating field names by a dot, e.g. Name.FullName.
  • Operator - string - the match operation to apply, one of <, <=, =, >, or >=.
  • Value - any - the value to match against.

Metadata

Metadata describes information about the state of the object.

  • ID - string - The unique identifier of the object.
  • Etag - string - An opaque string that changes whenever the object changes.
  • Created - Date - The date & time when the object was created.
  • Updated - Date - The data & time when the object was last modified.
Last modified May 12, 2020: refactor docs (d7a7a5c1d)