Skip to content

Commit

Permalink
Add optional external_id field to SCIM users and groups (#927)
Browse files Browse the repository at this point in the history
External ID could be propagated from linked identity provider, and is used for things like
Unity Catalog
  • Loading branch information
alexott committed Nov 18, 2021
1 parent 57d334d commit d891e49
Show file tree
Hide file tree
Showing 12 changed files with 38 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/data-sources/current_user.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ output "job_url" {
Data source exposes the following attributes:

* `id` - The id of the calling user.
* `external_id` - ID of the user in an external identity provider.
* `user_name` - Name of the [user](../resources/user.md), e.g. `mr.foo@example.com`.
* `home` - Home folder of the [user](../resources/user.md), e.g. `/Users/mr.foo@example.com`.
* `repos` - Personal Repos location of the [user](../resources/user.md), e.g. `/Repos/mr.foo@example.com`.
Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Data source allows you to pick groups by the following attributes
Data source exposes the following attributes:

* `id` - The id for the group object.
* `external_id` - ID of the group in an external identity provider.
* `members` - Set of [user](../resources/user.md) identifiers, that can be modified with [databricks_group_member](../resources/group_member.md) resource.
* `groups` - Set of [group](../resources/group.md) identifiers, that can be modified with [databricks_group_member](../resources/group_member.md) resource.
* `instance_profiles` - Set of [instance profile](../resources/instance_profile.md) ARNs, that can be modified by [databricks_group_instance_profile](../resources/group_instance_profile.md) resource.
Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Data source allows you to pick groups by the following attributes
Data source exposes the following attributes:

- `id` - The id of the user.
- `external_id` - ID of the user in an external identity provider.
- `user_name` - Name of the [user](../resources/user.md), e.g. `mr.foo@example.com`.
- `display_name` - Display name of the [user](../resources/user.md), e.g. `Mr Foo`.
- `home` - Home folder of the [user](../resources/user.md), e.g. `/Users/mr.foo@example.com`.
Expand Down
1 change: 1 addition & 0 deletions docs/resources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ resource "databricks_group_member" "vip_member" {
The following arguments are supported:

* `display_name` - (Required) This is the display name for the given group.
* `external_id` - (Optional) ID of the group in an external identity provider.
* `allow_cluster_create` - (Optional) This is a field to allow the group to have [cluster](cluster.md) create privileges. More fine grained permissions could be assigned with [databricks_permissions](permissions.md#Cluster-usage) and [cluster_id](permissions.md#cluster_id) argument. Everyone without `allow_cluster_create` argument set, but with [permission to use](permissions.md#Cluster-Policy-usage) Cluster Policy would be able to create clusters, but within boundaries of that specific policy.
* `allow_instance_pool_create` - (Optional) This is a field to allow the group to have [instance pool](instance_pool.md) create privileges. More fine grained permissions could be assigned with [databricks_permissions](permissions.md#Instance-Pool-usage) and [instance_pool_id](permissions.md#instance_pool_id) argument.
* `allow_sql_analytics_access` - (Optional) This is a field to allow the group to have access to [Databricks SQL](https://databricks.com/product/databricks-sql) feature through [databricks_sql_endpoint](sql_endpoint.md).
Expand Down
1 change: 1 addition & 0 deletions docs/resources/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The following arguments are available:

* `user_name` - (Required) This is the username of the given user and will be their form of access and identity.
* `display_name` - (Optional) This is an alias for the username that can be the full name of the user.
* `external_id` - (Optional) ID of the user in an external identity provider.
* `allow_cluster_create` - (Optional) Allow the user to have [cluster](cluster.md) create privileges. Defaults to false. More fine grained permissions could be assigned with [databricks_permissions](permissions.md#Cluster-usage) and `cluster_id` argument. Everyone without `allow_cluster_create` argument set, but with [permission to use](permissions.md#Cluster-Policy-usage) Cluster Policy would be able to create clusters, but within boundaries of that specific policy.
* `allow_instance_pool_create` - (Optional) Allow the user to have [instance pool](instance_pool.md) create privileges. Defaults to false. More fine grained permissions could be assigned with [databricks_permissions](permissions.md#Instance-Pool-usage) and [instance_pool_id](permissions.md#instance_pool_id) argument.
* `allow_sql_analytics_access` - (Optional) This is a field to allow the group to have access to [Databricks SQL](https://databricks.com/product/sql-analytics) feature through [databricks_sql_endpoint](sql_endpoint.md).
Expand Down
5 changes: 5 additions & 0 deletions identity/data_current_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func DataSourceCurrentUser() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Computed: true,
},
},
ReadContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
usersAPI := NewUsersAPI(ctx, m)
Expand All @@ -42,6 +46,7 @@ func DataSourceCurrentUser() *schema.Resource {
d.Set("user_name", me.UserName)
d.Set("home", fmt.Sprintf("/Users/%s", me.UserName))
d.Set("repos", fmt.Sprintf("/Repos/%s", me.UserName))
d.Set("external_id", me.ExternalID)
splits := strings.Split(me.UserName, "@")
norm := nonAlphanumeric.ReplaceAllLiteralString(splits[0], "_")
norm = strings.ToLower(norm)
Expand Down
2 changes: 2 additions & 0 deletions identity/data_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func DataSourceGroup() *schema.Resource {
Members []string `json:"members,omitempty" tf:"slice_set,computed"`
Groups []string `json:"groups,omitempty" tf:"slice_set,computed"`
InstanceProfiles []string `json:"instance_profiles,omitempty" tf:"slice_set,computed"`
ExternalID string `json:"external_id,omitempty" tf:"computed"`
}

s := common.StructToSchema(entity{}, func(
Expand Down Expand Up @@ -65,6 +66,7 @@ func DataSourceGroup() *schema.Resource {
}
}
}
this.ExternalID = group.ExternalID
sort.Strings(this.Groups)
sort.Strings(this.Members)
sort.Strings(this.InstanceProfiles)
Expand Down
10 changes: 10 additions & 0 deletions identity/data_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func DataSourceUser() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"repos": {
Type: schema.TypeString,
Computed: true,
},
"display_name": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -51,6 +55,10 @@ func DataSourceUser() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Computed: true,
},
},
ReadContext: func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
usersAPI := NewUsersAPI(ctx, m)
Expand All @@ -61,6 +69,8 @@ func DataSourceUser() *schema.Resource {
d.Set("user_name", user.UserName)
d.Set("display_name", user.DisplayName)
d.Set("home", fmt.Sprintf("/Users/%s", user.UserName))
d.Set("repos", fmt.Sprintf("/Repos/%s", user.UserName))
d.Set("external_id", user.ExternalID)
splits := strings.Split(user.UserName, "@")
norm := nonAlphanumeric.ReplaceAllLiteralString(splits[0], "_")
norm = strings.ToLower(norm)
Expand Down
3 changes: 2 additions & 1 deletion identity/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (a GroupsAPI) Patch(groupID string, r patchRequest) error {
return a.client.Scim(a.context, http.MethodPatch, fmt.Sprintf("/preview/scim/v2/Groups/%v", groupID), r, nil)
}

func (a GroupsAPI) UpdateNameAndEntitlements(groupID string, name string, e entitlements) error {
func (a GroupsAPI) UpdateNameAndEntitlements(groupID string, name string, externalID string, e entitlements) error {
g, err := a.Read(groupID)
if err != nil {
return err
Expand All @@ -80,6 +80,7 @@ func (a GroupsAPI) UpdateNameAndEntitlements(groupID string, name string, e enti
Roles: g.Roles,
Members: g.Members,
Schemas: []URN{GroupSchema},
ExternalID: externalID,
}, nil)
}

Expand Down
10 changes: 9 additions & 1 deletion identity/resource_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ func ResourceGroup() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"external_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
}
addEntitlementsToSchema(&groupSchema)
return common.Resource{
Expand All @@ -27,6 +32,7 @@ func ResourceGroup() *schema.Resource {
group, err := NewGroupsAPI(ctx, c).Create(ScimGroup{
DisplayName: groupName,
Entitlements: readEntitlementsFromData(d),
ExternalID: d.Get("external_id").(string),
})
if err != nil {
return err
Expand All @@ -40,12 +46,14 @@ func ResourceGroup() *schema.Resource {
return err
}
d.Set("display_name", group.DisplayName)
d.Set("external_id", group.ExternalID)
d.Set("url", c.FormatURL("#setting/accounts/groups/", d.Id()))
return group.Entitlements.readIntoData(d)
},
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
groupName := d.Get("display_name").(string)
return NewGroupsAPI(ctx, c).UpdateNameAndEntitlements(d.Id(), groupName, readEntitlementsFromData(d))
return NewGroupsAPI(ctx, c).UpdateNameAndEntitlements(d.Id(), groupName,
d.Get("external_id").(string), readEntitlementsFromData(d))
},
Delete: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
return NewGroupsAPI(ctx, c).Delete(d.Id())
Expand Down
3 changes: 3 additions & 0 deletions identity/resource_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func ResourceUser() *schema.Resource {
UserName string `json:"user_name" tf:"force_new"`
DisplayName string `json:"display_name,omitempty" tf:"computed"`
Active bool `json:"active,omitempty"`
ExternalID string `json:"external_id,omitempty"`
}
userSchema := common.StructToSchema(entity{},
func(m map[string]*schema.Schema) map[string]*schema.Schema {
Expand All @@ -31,6 +32,7 @@ func ResourceUser() *schema.Resource {
DisplayName: u.DisplayName,
Active: u.Active,
Entitlements: readEntitlementsFromData(d),
ExternalID: u.ExternalID,
}, nil
}
return common.Resource{
Expand All @@ -55,6 +57,7 @@ func ResourceUser() *schema.Resource {
d.Set("user_name", user.UserName)
d.Set("display_name", user.DisplayName)
d.Set("active", user.Active)
d.Set("external_id", user.ExternalID)
return user.Entitlements.readIntoData(d)
},
Update: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
Expand Down
2 changes: 2 additions & 0 deletions identity/scim.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type ScimGroup struct {
Groups []ComplexValue `json:"groups,omitempty"`
Roles []ComplexValue `json:"roles,omitempty"`
Entitlements entitlements `json:"entitlements,omitempty"`
ExternalID string `json:"externalId,omitempty"`
}

// GroupList contains a list of groups fetched from a list api call from SCIM api
Expand Down Expand Up @@ -128,6 +129,7 @@ type ScimUser struct {
Name map[string]string `json:"name,omitempty"`
Roles []ComplexValue `json:"roles,omitempty"`
Entitlements entitlements `json:"entitlements,omitempty"`
ExternalID string `json:"externalId,omitempty"`
}

// UserList contains a list of Users fetched from a list api call from SCIM api
Expand Down

0 comments on commit d891e49

Please sign in to comment.