Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
## Enhancements
* Adds the `ProviderType` field to `AdminSAMLSetting` and `AdminSAMLSettingsUpdateOptions` to support the `provider-type` SAML setting by @skj-skj [#1303](https://github.com/hashicorp/go-tfe/pull/1303)
* Adds `AdminSCIMSetting` to support managing site-level SCIM settings by @skj-skj [#1307](https://github.com/hashicorp/go-tfe/pull/1307)
* Adds `AdminSCIMToken` to support managing site-level SCIM tokens by @skj-skj [#1310](https://github.com/hashicorp/go-tfe/pull/1310)

# v1.103.0

Expand Down
13 changes: 11 additions & 2 deletions admin_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

package tfe

// SCIMResource groups the SCIM related resources together.
type SCIMResource struct {
SCIMSettings
Token AdminSCIMTokens
}
Comment thread
skj-skj marked this conversation as resolved.

// AdminSettings describes all the admin settings related methods that the Terraform Enterprise API supports.
// Note that admin settings are only available in Terraform Enterprise.
//
Expand All @@ -15,7 +21,7 @@ type AdminSettings struct {
Twilio TwilioSettings
Customization CustomizationSettings
OIDC OIDCSettings
SCIM SCIMSettings
SCIM *SCIMResource
}
Comment thread
skj-skj marked this conversation as resolved.

func newAdminSettings(client *Client) *AdminSettings {
Expand All @@ -27,6 +33,9 @@ func newAdminSettings(client *Client) *AdminSettings {
Twilio: &adminTwilioSettings{client: client},
Customization: &adminCustomizationSettings{client: client},
OIDC: &adminOIDCSettings{client: client},
SCIM: &adminSCIMSettings{client: client},
SCIM: &SCIMResource{
SCIMSettings: &adminSCIMSettings{client: client},
Token: &adminSCIMTokens{client: client},
},
}
}
31 changes: 3 additions & 28 deletions admin_setting_scim_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package tfe
import (
"context"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -87,8 +86,9 @@ func TestAdminSettings_SCIM_Update(t *testing.T) {
_, err = scimClient.Update(ctx, AdminSCIMSettingUpdateOptions{Enabled: Bool(true)})
require.NoError(t, err)

scimToken := generateSCIMToken(ctx, t, client)
scimGroupID := createSCIMGroup(ctx, t, client, "foo", scimToken)
scimToken, err := scimClient.Token.Create(ctx)
require.NoError(t, err)
Comment thread
skj-skj marked this conversation as resolved.
Comment thread
skj-skj marked this conversation as resolved.
scimGroupID := createSCIMGroup(ctx, t, client, "foo", scimToken.Token)

testCases := []struct {
name string
Expand Down Expand Up @@ -169,28 +169,3 @@ func cleanupSCIMSettings(ctx context.Context, t *testing.T, client *Client) {
err = setSAMLProviderType(ctx, t, client, false)
require.NoErrorf(t, err, "failed to set SAML provider type")
}

// generate a SCIM token for testing
func generateSCIMToken(ctx context.Context, t *testing.T, client *Client) string {
t.Helper()
// TFE requires a minimum of 30 days for SCIM token expiration
expiredAt := time.Now().Add(30 * 24 * time.Hour)

options := struct {
Description *string `jsonapi:"attr,description"`
ExpiredAt *time.Time `jsonapi:"attr,expired-at,iso8601"`
}{
Description: String("test-scim-token"),
ExpiredAt: &expiredAt,
}
req, err := client.NewRequest("POST", "admin/scim-tokens", &options)
require.NoError(t, err)

var res struct {
Token string `jsonapi:"attr,token"`
}
err = req.Do(ctx, &res)
require.NoError(t, err)

return res.Token
}
128 changes: 128 additions & 0 deletions admin_setting_scim_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package tfe

Comment thread
skj-skj marked this conversation as resolved.
import (
"context"
"fmt"
"net/url"
"time"
)

var _ AdminSCIMTokens = (*adminSCIMTokens)(nil)

// AdminSCIMTokens describes all the admin scim token related methods that the Terraform
// Enterprise API supports
//
// TFE API docs: https://developer.hashicorp.com/terraform/enterprise/api-docs/admin/scim-tokens
type AdminSCIMTokens interface {
// List all admin scim tokens.
List(ctx context.Context) (*AdminSCIMTokenList, error)

// Create a admin scim token.
Create(ctx context.Context) (*AdminSCIMToken, error)

// Create a admin scim token with options.
CreateWithOptions(ctx context.Context, options AdminSCIMTokenCreateOptions) (*AdminSCIMToken, error)

// Read a admin scim token by its ID.
Comment thread
skj-skj marked this conversation as resolved.
Outdated
ReadByID(ctx context.Context, scimTokenID string) (*AdminSCIMToken, error)

// Delete a admin scim token.
Delete(ctx context.Context, scimTokenID string) error
Comment thread
skj-skj marked this conversation as resolved.
Outdated
}

// adminSCIMTokens implements AdminSCIMTokens
type adminSCIMTokens struct {
client *Client
}

// AdminSCIMTokenList represents a list of admin scim tokens
type AdminSCIMTokenList struct {
Comment thread
skj-skj marked this conversation as resolved.
Comment thread
skj-skj marked this conversation as resolved.
Items []*AdminSCIMToken
}
Comment thread
skj-skj marked this conversation as resolved.

// AdminSCIMToken represents a Terraform Enterprise scim token.
type AdminSCIMToken struct {
ID string `jsonapi:"primary,authentication-tokens"`
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
LastUsedAt time.Time `jsonapi:"attr,last-used-at,iso8601"`
ExpiredAt time.Time `jsonapi:"attr,expired-at,iso8601"`
Description string `jsonapi:"attr,description"`
Token string `jsonapi:"attr,token,omitempty"`
}

// AdminSCIMTokenCreateOptions represents the options for creating a admin scim token
type AdminSCIMTokenCreateOptions struct {

Comment thread
skj-skj marked this conversation as resolved.
Outdated
// Optional: An optional human-readable description of the token's purpose
// (for example, Okta SCIM Integration).
Description *string `jsonapi:"attr,description,omitempty"`

// Optional: Optional ISO-8601 timestamp for token expiration.
// Defaults to 365 days in the future. Must be between 29 and 365 days in the future.
ExpiredAt *time.Time `jsonapi:"attr,expired-at,iso8601,omitempty"`
}

// List all admin scim tokens.
func (a *adminSCIMTokens) List(ctx context.Context) (*AdminSCIMTokenList, error) {
req, err := a.client.NewRequest("GET", "admin/scim-tokens", nil)
if err != nil {
return nil, err
}

scimTokens := &AdminSCIMTokenList{}
err = req.Do(ctx, scimTokens)
if err != nil {
return nil, err
}
return scimTokens, nil
}

// Create a admin scim token.
func (a *adminSCIMTokens) Create(ctx context.Context) (*AdminSCIMToken, error) {
return a.CreateWithOptions(ctx, AdminSCIMTokenCreateOptions{})
Comment thread
skj-skj marked this conversation as resolved.
Outdated
}

// Create a admin scim token with options.
func (a *adminSCIMTokens) CreateWithOptions(ctx context.Context, options AdminSCIMTokenCreateOptions) (*AdminSCIMToken, error) {
req, err := a.client.NewRequest("POST", "admin/scim-tokens", &options)
Comment thread
skj-skj marked this conversation as resolved.
Outdated
if err != nil {
return nil, err
}
scimToken := &AdminSCIMToken{}
err = req.Do(ctx, scimToken)
if err != nil {
return nil, err
}
return scimToken, nil
}

// Read a admin scim token by its ID.
func (a *adminSCIMTokens) ReadByID(ctx context.Context, scimTokenID string) (*AdminSCIMToken, error) {
if !validStringID(&scimTokenID) {
return nil, ErrInvalidTokenID
}
u := fmt.Sprintf("admin/scim-tokens/%s", url.PathEscape(scimTokenID))
req, err := a.client.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
scimToken := &AdminSCIMToken{}
err = req.Do(ctx, scimToken)
if err != nil {
return nil, err
}
return scimToken, nil
}

// Delete a admin scim token.
func (a *adminSCIMTokens) Delete(ctx context.Context, scimTokenID string) error {
if !validStringID(&scimTokenID) {
return ErrInvalidTokenID
}
u := fmt.Sprintf(AuthenticationTokensPath, url.PathEscape(scimTokenID))
Comment thread
skj-skj marked this conversation as resolved.
req, err := a.client.NewRequest("DELETE", u, nil)
if err != nil {
return err
}
return req.Do(ctx, nil)
}
Loading
Loading