Grouper SCIM can provision groups, entities and memberships to Tableau.

External system

Go to settings in Tableau and enable SCIM, use the URL and the token

Groups

The displayName SCIM attribute for groups can be mapped to something in Grouper.  If you want special chars perhaps use displayExtension.  Otherwise the extension.  The groups in Grouper can be in the same folder so there are no conflicts.  Map the id as usual for SCIM


Entities

There is a bizarre Tableau name issue (in 2024, maybe fixed subsequently) where the user's first and last name is set in SAML but cannot be set in SCIM.  These attributes can be mapped

  • id
  • email
  • familyName
  • givenName
  • userName
  • displayName


SampleConfig

provisioner.TableauProvisioner.addDisabledFullSyncDaemon = true
provisioner.TableauProvisioner.addDisabledIncrementalSyncDaemon = true
provisioner.TableauProvisioner.bearerTokenExternalSystemConfigId = Tableau
provisioner.TableauProvisioner.class = edu.internet2.middleware.grouper.app.scim2Provisioning.GrouperScim2Provisioner
provisioner.TableauProvisioner.customizeEntityCrud = true
provisioner.TableauProvisioner.customizeGroupCrud = true
provisioner.TableauProvisioner.customizeMembershipCrud = false
provisioner.TableauProvisioner.deleteEntities = false
provisioner.TableauProvisioner.deleteGroups = false
provisioner.TableauProvisioner.entityAttributeValueCache0entityAttribute = id
provisioner.TableauProvisioner.entityAttributeValueCache0has = true
provisioner.TableauProvisioner.entityAttributeValueCache0source = target
provisioner.TableauProvisioner.entityAttributeValueCache0type = entityAttribute
provisioner.TableauProvisioner.entityAttributeValueCache1entityAttribute = userName
provisioner.TableauProvisioner.entityAttributeValueCache1has = true
provisioner.TableauProvisioner.entityAttributeValueCache1source = target
provisioner.TableauProvisioner.entityAttributeValueCache1type = entityAttribute
provisioner.TableauProvisioner.entityAttributeValueCache2has = true
provisioner.TableauProvisioner.entityAttributeValueCache2source = grouper
provisioner.TableauProvisioner.entityAttributeValueCache2translationScript = ${subject.getAttributeValue('sn')}
provisioner.TableauProvisioner.entityAttributeValueCache2type = subjectTranslationScript
provisioner.TableauProvisioner.entityAttributeValueCache3has = true
provisioner.TableauProvisioner.entityAttributeValueCache3source = grouper
provisioner.TableauProvisioner.entityAttributeValueCache3translationScript = ${subject.getAttributeValue('givenName')}
provisioner.TableauProvisioner.entityAttributeValueCache3type = subjectTranslationScript
provisioner.TableauProvisioner.entityAttributeValueCacheHas = true
provisioner.TableauProvisioner.entityMatchingAttribute0name = userName
provisioner.TableauProvisioner.entityMatchingAttribute1name = id
provisioner.TableauProvisioner.entityMatchingAttributeCount = 2
provisioner.TableauProvisioner.groupAttributeValueCache0groupAttribute = id
provisioner.TableauProvisioner.groupAttributeValueCache0has = true
provisioner.TableauProvisioner.groupAttributeValueCache0source = target
provisioner.TableauProvisioner.groupAttributeValueCache0type = groupAttribute
provisioner.TableauProvisioner.groupAttributeValueCache1groupAttribute = displayName
provisioner.TableauProvisioner.groupAttributeValueCache1has = true
provisioner.TableauProvisioner.groupAttributeValueCache1source = target
provisioner.TableauProvisioner.groupAttributeValueCache1type = groupAttribute
provisioner.TableauProvisioner.groupAttributeValueCacheHas = true
provisioner.TableauProvisioner.groupMatchingAttribute0name = displayName
provisioner.TableauProvisioner.groupMatchingAttributeCount = 1
provisioner.TableauProvisioner.hasTargetEntityLink = true
provisioner.TableauProvisioner.hasTargetGroupLink = true
provisioner.TableauProvisioner.logAllObjectsVerbose = true
provisioner.TableauProvisioner.logCommandsAlways = true
provisioner.TableauProvisioner.makeChangesToEntities = true
provisioner.TableauProvisioner.numberOfEntityAttributes = 6
provisioner.TableauProvisioner.numberOfGroupAttributes = 2
provisioner.TableauProvisioner.operateOnGrouperEntities = true
provisioner.TableauProvisioner.operateOnGrouperGroups = true
provisioner.TableauProvisioner.operateOnGrouperMemberships = true
provisioner.TableauProvisioner.provisioningType = membershipObjects
provisioner.TableauProvisioner.scimType = generic
provisioner.TableauProvisioner.selectAllEntities = true
provisioner.TableauProvisioner.selectAllGroups = true
provisioner.TableauProvisioner.showAdvanced = true
provisioner.TableauProvisioner.startWith = this is start with read only
provisioner.TableauProvisioner.subjectSourcesToProvision = fischerLdapProd
provisioner.TableauProvisioner.targetEntityAttribute.0.insert = false
provisioner.TableauProvisioner.targetEntityAttribute.0.name = id
provisioner.TableauProvisioner.targetEntityAttribute.0.showAdvancedAttribute = true
provisioner.TableauProvisioner.targetEntityAttribute.0.showAttributeCrud = true
provisioner.TableauProvisioner.targetEntityAttribute.1.name = emailValue
provisioner.TableauProvisioner.targetEntityAttribute.1.translateExpression = ${grouperProvisioningEntity.getSubjectId() + '@isu.edu'}
provisioner.TableauProvisioner.targetEntityAttribute.1.translateExpressionType = translationScript
provisioner.TableauProvisioner.targetEntityAttribute.2.name = familyName
provisioner.TableauProvisioner.targetEntityAttribute.2.translateExpressionType = grouperProvisioningEntityField
provisioner.TableauProvisioner.targetEntityAttribute.2.translateFromGrouperProvisioningEntityField = entityAttributeValueCache2
provisioner.TableauProvisioner.targetEntityAttribute.3.name = givenName
provisioner.TableauProvisioner.targetEntityAttribute.3.translateExpressionType = grouperProvisioningEntityField
provisioner.TableauProvisioner.targetEntityAttribute.3.translateFromGrouperProvisioningEntityField = entityAttributeValueCache3
provisioner.TableauProvisioner.targetEntityAttribute.4.name = userName
provisioner.TableauProvisioner.targetEntityAttribute.4.translateExpression = ${grouperProvisioningEntity.getSubjectId() + '@isu.edu'}
provisioner.TableauProvisioner.targetEntityAttribute.4.translateExpressionType = translationScript
provisioner.TableauProvisioner.targetEntityAttribute.5.name = displayName
provisioner.TableauProvisioner.targetEntityAttribute.5.translateExpressionType = grouperProvisioningEntityField
provisioner.TableauProvisioner.targetEntityAttribute.5.translateFromGrouperProvisioningEntityField = name
provisioner.TableauProvisioner.targetGroupAttribute.0.insert = false
provisioner.TableauProvisioner.targetGroupAttribute.0.name = id
provisioner.TableauProvisioner.targetGroupAttribute.0.showAdvancedAttribute = true
provisioner.TableauProvisioner.targetGroupAttribute.0.showAttributeCrud = true
provisioner.TableauProvisioner.targetGroupAttribute.1.name = displayName
provisioner.TableauProvisioner.targetGroupAttribute.1.translateExpressionType = grouperProvisioningGroupField
provisioner.TableauProvisioner.targetGroupAttribute.1.translateFromGrouperProvisioningGroupField = displayExtension
provisioner.TableauProvisioner.updateEntities = false
provisioner.TableauProvisioner.updateGroups = false

1 Comment

  1. We got this to work at SLAC... it was a simpler config.  We only provision the entity attributes of id, email, userName.  Here is our config:

    provisioner.TableauScim.addDisabledFullSyncDaemon = true
    provisioner.TableauScim.addDisabledIncrementalSyncDaemon = true
    provisioner.TableauScim.bearerTokenExternalSystemConfigId = TableauCloudScim
    provisioner.TableauScim.class = edu.internet2.middleware.grouper.app.scim2Provisioning.GrouperScim2Provisioner
    provisioner.TableauScim.customizeGroupCrud = true
    provisioner.TableauScim.deleteGroupsIfGrouperDeleted = true
    provisioner.TableauScim.entityAttributeValueCache0entityAttribute = id
    provisioner.TableauScim.entityAttributeValueCache0has = true
    provisioner.TableauScim.entityAttributeValueCache0source = target
    provisioner.TableauScim.entityAttributeValueCache0type = entityAttribute
    provisioner.TableauScim.entityAttributeValueCacheHas = true
    provisioner.TableauScim.entityMatchingAttribute0name = userName
    provisioner.TableauScim.entityMatchingAttributeCount = 1
    provisioner.TableauScim.groupAttributeValueCache0groupAttribute = id
    provisioner.TableauScim.groupAttributeValueCache0has = true
    provisioner.TableauScim.groupAttributeValueCache0source = target
    provisioner.TableauScim.groupAttributeValueCache0type = groupAttribute
    provisioner.TableauScim.groupAttributeValueCache1groupAttribute = displayName
    provisioner.TableauScim.groupAttributeValueCache1has = true
    provisioner.TableauScim.groupAttributeValueCache1source = target
    provisioner.TableauScim.groupAttributeValueCache1type = groupAttribute
    provisioner.TableauScim.groupAttributeValueCacheHas = true
    provisioner.TableauScim.groupMatchingAttribute0name = displayName
    provisioner.TableauScim.groupMatchingAttribute1name = id
    provisioner.TableauScim.groupMatchingAttributeCount = 2
    provisioner.TableauScim.hasTargetEntityLink = true
    provisioner.TableauScim.hasTargetGroupLink = true
    provisioner.TableauScim.includeActiveOnGroupCreate = false
    provisioner.TableauScim.makeChangesToEntities = true
    provisioner.TableauScim.numberOfEntityAttributes = 3
    provisioner.TableauScim.numberOfGroupAttributes = 2
    provisioner.TableauScim.operateOnGrouperEntities = true
    provisioner.TableauScim.operateOnGrouperGroups = true
    provisioner.TableauScim.operateOnGrouperMemberships = true
    provisioner.TableauScim.provisioningType = membershipObjects
    provisioner.TableauScim.scimType = generic
    provisioner.TableauScim.selectAllEntities = true
    provisioner.TableauScim.showAdvanced = true
    provisioner.TableauScim.startWith = this is start with read only
    provisioner.TableauScim.subjectSourcesToProvision = slacPerson
    provisioner.TableauScim.targetEntityAttribute.0.insert = false
    provisioner.TableauScim.targetEntityAttribute.0.name = id
    provisioner.TableauScim.targetEntityAttribute.0.showAdvancedAttribute = true
    provisioner.TableauScim.targetEntityAttribute.0.showAttributeCrud = true
    provisioner.TableauScim.targetEntityAttribute.0.update = false
    provisioner.TableauScim.targetEntityAttribute.1.name = emailValue
    provisioner.TableauScim.targetEntityAttribute.1.translateExpressionType = grouperProvisioningEntityField
    provisioner.TableauScim.targetEntityAttribute.1.translateFromGrouperProvisioningEntityField = email
    provisioner.TableauScim.targetEntityAttribute.2.name = userName
    provisioner.TableauScim.targetEntityAttribute.2.translateExpressionType = grouperProvisioningEntityField
    provisioner.TableauScim.targetEntityAttribute.2.translateFromGrouperProvisioningEntityField = subjectId
    provisioner.TableauScim.targetGroupAttribute.0.insert = false
    provisioner.TableauScim.targetGroupAttribute.0.name = id
    provisioner.TableauScim.targetGroupAttribute.0.showAdvancedAttribute = true
    provisioner.TableauScim.targetGroupAttribute.0.showAttributeCrud = true
    provisioner.TableauScim.targetGroupAttribute.1.name = displayName
    provisioner.TableauScim.targetGroupAttribute.1.translateExpressionType = grouperProvisioningGroupField
    provisioner.TableauScim.targetGroupAttribute.1.translateFromGrouperProvisioningGroupField = extension
    provisioner.TableauScim.updateGroups = false