From 4dd9ba60fe3663d5913648aeecf264aa82abae66 Mon Sep 17 00:00:00 2001 From: Bruce MacDonald Date: Mon, 1 Nov 2021 09:30:19 -0400 Subject: [PATCH] Migrate from "Sources" to "Providers" (#518) - Renames sources to providers - Move CLI config migrations to one file - Add secrets to dev config - Update identity provider config loading to match secrets --- README.md | 17 +- docker-desktop.yaml.in | 12 +- docs/configuration.md | 55 +++--- docs/{sources => providers}/okta.md | 50 +++-- helm/charts/infra/templates/NOTES.txt | 2 +- helm/charts/infra/templates/configmap.yaml | 2 +- .../api/{api_sources.go => api_providers.go} | 62 +++--- internal/api/client.go | 6 +- internal/api/model_group.go | 38 ++-- .../{model_source.go => model_provider.go} | 112 +++++------ ..._source_okta.go => model_provider_okta.go} | 44 ++--- internal/cmd/cmd.go | 2 +- internal/cmd/{config0dot2.go => config.go} | 29 ++- internal/cmd/config0dot1.go | 26 --- internal/cmd/config_migration.go | 60 ++++++ internal/cmd/login.go | 54 ++--- internal/registry/_testdata/infra.yaml | 26 ++- internal/registry/api.go | 70 +++---- internal/registry/api_test.go | 80 ++++---- internal/registry/config.go | 186 +++++++++++------- internal/registry/config_test.go | 48 ++--- internal/registry/data.go | 112 +++++------ internal/registry/data_test.go | 20 +- internal/registry/registry.go | 60 +++--- internal/registry/telemetry.go | 6 +- .../apis/{SourcesApi.ts => ProvidersApi.ts} | 42 ++-- internal/registry/ui/api/apis/index.ts | 2 +- internal/registry/ui/api/models/Group.ts | 6 +- .../ui/api/models/{Source.ts => Provider.ts} | 44 ++--- .../models/{SourceOkta.ts => ProviderOkta.ts} | 14 +- internal/registry/ui/api/models/index.ts | 4 +- openapi.yaml | 32 +-- openapi/group.yaml | 4 +- openapi/{source.yaml => provider.yaml} | 6 +- 34 files changed, 709 insertions(+), 624 deletions(-) rename docs/{sources => providers}/okta.md (75%) rename internal/api/{api_sources.go => api_providers.go} (80%) rename internal/api/{model_source.go => model_provider.go} (63%) rename internal/api/{model_source_okta.go => model_provider_okta.go} (56%) rename internal/cmd/{config0dot2.go => config.go} (77%) delete mode 100644 internal/cmd/config0dot1.go create mode 100644 internal/cmd/config_migration.go rename internal/registry/ui/api/apis/{SourcesApi.ts => ProvidersApi.ts} (58%) rename internal/registry/ui/api/models/{Source.ts => Provider.ts} (66%) rename internal/registry/ui/api/models/{SourceOkta.ts => ProviderOkta.ts} (67%) rename openapi/{source.yaml => provider.yaml} (90%) diff --git a/README.md b/README.md index a7618cb4a0..79c5b4ca40 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This example configuration uses Okta and grants the "Everyone" group read-only a * Okta API token * Cluster name -See [Okta](./docs/sources/okta.md) for detailed Okta configuration steps. +See [Okta](./docs/providers/okta.md) for detailed Okta configuration steps. Cluster name is auto-discovered or can be set statically in Helm with `engine.name`. @@ -49,13 +49,12 @@ Also see [secrets.md](./docs/secrets.md) for details on how secrets work. # example values.yaml --- config: - sources: + providers: - kind: okta domain: - client-id: - client-secret: : - okta: - api-token: : + clientID: + clientSecret: : + apiToken: : groups: - name: Everyone roles: @@ -162,10 +161,10 @@ See the [Infra CLI reference](./docs/cli.md) for more ways to use `infra`. ## Next Steps -### Connect Additional Identity Sources +### Connect Additional Identity Providers -* [Sources](./docs/sources) - * [Okta](./docs/sources/okta.md) +* [Providers](./docs/providers) + * [Okta](./docs/providers/okta.md) ### Connect Additional Infrastructure Destinations diff --git a/docker-desktop.yaml.in b/docker-desktop.yaml.in index 5ffe83566f..1f46a9a54b 100644 --- a/docker-desktop.yaml.in +++ b/docker-desktop.yaml.in @@ -4,13 +4,15 @@ image: pullPolicy: Never config: - sources: + secrets: + - kind: kubernetes + namespace: infrahq + providers: - kind: okta domain: $OKTA_DOMAIN - client-id: $OKTA_CLIENT_ID - client-secret: $OKTA_SECRET/clientSecret - okta: - api-token: $OKTA_SECRET/apiToken + clientID: $OKTA_CLIENT_ID + clientSecret: kubernetes:$OKTA_SECRET/clientSecret + apiToken: kubernetes:$OKTA_SECRET/apiToken engine: name: docker-desktop diff --git a/docs/configuration.md b/docs/configuration.md index d8b4b621e8..bfaae385b6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -15,9 +15,12 @@ First, create a `values.yaml`. If a `values.yaml` already exists, update it to i # values.yaml --- config: - sources: [...] - groups: [...] - users: [...] + providers: + [...] + groups: + [...] + users: + [...] ``` See [Helm Chart reference](./helm.md) for a complete list of options configurable through Helm. @@ -33,9 +36,12 @@ helm -n infrahq upgrade -f values.yaml infra infrahq/infra First, create a config file `infra.yaml`: ``` -sources: [...] -groups: [...] -users: [...] +providers: + [...] +groups: + [...] +users: + [...] ``` Then, apply it to Infra: @@ -46,34 +52,34 @@ helm -n infrahq upgrade --set-file=config=infra.yaml infra infrahq/infra ## Reference -### `sources` +### `providers` -List of identity sources used to synchronize users and groups. +List of identity providers used to synchronize users and groups. | Parameter | Description | |----------------|----------------------------------------------| -| `kind` | Source type | -| | Additional source-specific parameters | +| `kind` | Provider type | +| | Additional provider-specific parameters | -See [Identity Sources](./sources/) for a full list of configurable values. +See [Identity Providers](./providers/) for a full list of configurable values. ### `groups` List of groups to assign access. -| Parameter | Description | -|----------------|----------------------------------------------| -| `name` | Group name as stored in the identity source | -| `roles` | Roles assigned to the user | +| Parameter | Description | +|----------------|-----------------------------------------------| +| `name` | Group name as stored in the identity provider | +| `roles` | Roles assigned to the user | ### `users` List of users to assign access. -| Parameter | Description | -|----------------|----------------------------------------------| -| `email` | User email as stored in the identity source | -| `roles` | Roles assigned to the user | +| Parameter | Description | +|----------------|-----------------------------------------------| +| `email` | User email as stored in the identity provider | +| `roles` | Roles assigned to the user | ### `roles` @@ -99,17 +105,16 @@ See [Infrastructure Destinations](./destinations/) for a full list of configurab ## Full Example ```yaml -sources: +providers: - kind: okta domain: acme.okta.com - client-id: 0oapn0qwiQPiMIyR35d6 - client-secret: kubernetes:infra-okta/clientSecret - okta: - api-token: kubernetes:infra-okta/apiToken + clientID: 0oapn0qwiQPiMIyR35d6 + clientSecret: kubernetes:infra-okta/clientSecret + apiToken: kubernetes:infra-okta/apiToken groups: - name: administrators - source: okta + provider: okta roles: - name: cluster-admin kind: cluster-role diff --git a/docs/sources/okta.md b/docs/providers/okta.md similarity index 75% rename from docs/sources/okta.md rename to docs/providers/okta.md index adb9dcf5b6..d2f138ef06 100644 --- a/docs/sources/okta.md +++ b/docs/providers/okta.md @@ -1,27 +1,25 @@ -# Sources / Okta +# Providers / Okta -## Configure Okta Source +## Configure Okta Provider -| Parameter | Field | Description | -|-----------------|-------------|-----------------------------| -| `domain` | | Okta domain | -| `client-id` | | Okta client ID | -| `client-secret` | | Okta client secret | -| `okta` | | Okta specific configuration | -| `okta` | `api-token` | Okta API token | +| Parameter | Description | +|-----------------|-----------------------------| +| `domain` | Okta domain | +| `clientID` | Okta client ID | +| `clientSecret` | Okta client secret | +| `apiToken` | Okta API token | -## Connect an Okta Source +## Connect an Okta Provider -This guide will walk you through the process of setting up Okta as an identity provider for Infra. At the end of this process you will have updated your Infra configuration with an Okta source that looks something like this: +This guide will walk you through the process of setting up Okta as an identity provider for Infra. At the end of this process you will have updated your Infra configuration with an Okta provider that looks something like this: ``` -sources: +providers: - kind: okta domain: acme.okta.com - client-id: 0oapn0qwiQPiMIyR35d6 - client-secret: kubernetes:infra-okta/clientSecret - okta: - api-token: kubernetes:infra-okta/apiToken + clientID: 0oapn0qwiQPiMIyR35d6 + clientSecret: kubernetes:infra-okta/clientSecret + apiToken: kubernetes:infra-okta/apiToken ``` ## Create an Okta App @@ -67,18 +65,17 @@ see [secrets.md](../secrets.md) for further details. ## Add Okta Information to Infra Configuration -Edit your [Infra configuration](./configuration.md) (e.g. `infra.yaml`) to include an Okta source: +Edit your [Infra configuration](./configuration.md) (e.g. `infra.yaml`) to include an Okta provider: ```yaml # infra.yaml --- -sources: +providers: - kind: okta domain: example.okta.com - client-id: 0oapn0qwiQPiMIyR35d6 - client-secret: kubernetes:infra-okta/clientSecret # : - okta: - api-token: kubernetes:infra-okta/apiToken + clientID: 0oapn0qwiQPiMIyR35d6 + clientSecret: kubernetes:infra-okta/clientSecret # : + apiToken: kubernetes:infra-okta/apiToken ``` Then apply this config change: @@ -93,13 +90,12 @@ Infra configuration can also be added to Helm values: # values.yaml --- config: - sources: + providers: - kind: okta domain: example.okta.com - client-id: 0oapn0qwiQPiMIyR35d6 - client-secret: kubernetes:infra-okta/clientSecret # : - okta: - api-token: kubernetes:infra-okta/apiToken + clientID: 0oapn0qwiQPiMIyR35d6 + clientSecret: kubernetes:infra-okta/clientSecret # : + apiToken: kubernetes:infra-okta/apiToken ``` Then apply this config change: diff --git a/helm/charts/infra/templates/NOTES.txt b/helm/charts/infra/templates/NOTES.txt index 49efe47150..5bd2e2c1c1 100644 --- a/helm/charts/infra/templates/NOTES.txt +++ b/helm/charts/infra/templates/NOTES.txt @@ -28,7 +28,7 @@ Next steps: - * Connect additional identity sources: https://github.com/infrahq/infra/blob/main/docs/sources/ + * Connect additional identity providers: https://github.com/infrahq/infra/blob/main/docs/providers/ * Connect additional infrastructure destinations: https://github.com/infrahq/infra/blob/main/docs/destinations/ ************************************************* diff --git a/helm/charts/infra/templates/configmap.yaml b/helm/charts/infra/templates/configmap.yaml index 5984f33bd4..b6ce1e8f97 100644 --- a/helm/charts/infra/templates/configmap.yaml +++ b/helm/charts/infra/templates/configmap.yaml @@ -20,7 +20,7 @@ data: {{- $options := list "config-path" "db-file" "tls-cache" }} {{- $options = list "root-api-key" "engine-api-key" | concat $options }} {{- $options = list "enable-ui" "ui-proxy" | concat $options }} -{{- $options = list "sources-sync-interval" "destinations-sync-interval" | concat $options }} +{{- $options = list "providers-sync-interval" "destinations-sync-interval" | concat $options }} {{- $options = list "enable-telemetry" "enable-crash-reporting" | concat $options }} {{- range $options }} {{- if hasKey $.Values . }} diff --git a/internal/api/api_sources.go b/internal/api/api_providers.go similarity index 80% rename from internal/api/api_sources.go rename to internal/api/api_providers.go index 7faecbd4a1..1ac066c805 100644 --- a/internal/api/api_sources.go +++ b/internal/api/api_providers.go @@ -24,28 +24,28 @@ var ( _ _context.Context ) -// SourcesAPIService SourcesAPI service -type SourcesAPIService service +// ProvidersAPIService ProvidersAPI service +type ProvidersAPIService service -type APIGetSourceRequest struct { +type APIGetProviderRequest struct { ctx _context.Context - APIService *SourcesAPIService + APIService *ProvidersAPIService id string } -func (r APIGetSourceRequest) Execute() (Source, *_nethttp.Response, error) { - return r.APIService.GetSourceExecute(r) +func (r APIGetProviderRequest) Execute() (Provider, *_nethttp.Response, error) { + return r.APIService.GetProviderExecute(r) } /* -GetSource Get source by ID +GetProvider Get provider by ID @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @param id Source ID - @return APIGetSourceRequest + @param id Provider ID + @return APIGetProviderRequest */ -func (a *SourcesAPIService) GetSource(ctx _context.Context, id string) APIGetSourceRequest { - return APIGetSourceRequest{ +func (a *ProvidersAPIService) GetProvider(ctx _context.Context, id string) APIGetProviderRequest { + return APIGetProviderRequest{ APIService: a, ctx: ctx, id: id, @@ -53,23 +53,23 @@ func (a *SourcesAPIService) GetSource(ctx _context.Context, id string) APIGetSou } // Execute executes the request -// @return Source -func (a *SourcesAPIService) GetSourceExecute(r APIGetSourceRequest) (Source, *_nethttp.Response, error) { +// @return Provider +func (a *ProvidersAPIService) GetProviderExecute(r APIGetProviderRequest) (Provider, *_nethttp.Response, error) { var ( localVarHTTPMethod = _nethttp.MethodGet localVarPostBody interface{} localVarFormFileName string localVarFileName string localVarFileBytes []byte - localVarReturnValue Source + localVarReturnValue Provider ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "SourcesAPIService.GetSource") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProvidersAPIService.GetProvider") if err != nil { return localVarReturnValue, nil, GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/sources/{id}" + localVarPath := localBasePath + "/providers/{id}" localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", _neturl.PathEscape(parameterToString(r.id, "")), -1) localVarHeaderParams := make(map[string]string) @@ -137,53 +137,53 @@ func (a *SourcesAPIService) GetSourceExecute(r APIGetSourceRequest) (Source, *_n return localVarReturnValue, localVarHTTPResponse, nil } -type APIListSourcesRequest struct { +type APIListProvidersRequest struct { ctx _context.Context - APIService *SourcesAPIService + APIService *ProvidersAPIService kind *string } -// Filter sources by kind -func (r APIListSourcesRequest) Kind(kind string) APIListSourcesRequest { +// Filter providers by kind +func (r APIListProvidersRequest) Kind(kind string) APIListProvidersRequest { r.kind = &kind return r } -func (r APIListSourcesRequest) Execute() ([]Source, *_nethttp.Response, error) { - return r.APIService.ListSourcesExecute(r) +func (r APIListProvidersRequest) Execute() ([]Provider, *_nethttp.Response, error) { + return r.APIService.ListProvidersExecute(r) } /* -ListSources List sources +ListProviders List providers @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return APIListSourcesRequest + @return APIListProvidersRequest */ -func (a *SourcesAPIService) ListSources(ctx _context.Context) APIListSourcesRequest { - return APIListSourcesRequest{ +func (a *ProvidersAPIService) ListProviders(ctx _context.Context) APIListProvidersRequest { + return APIListProvidersRequest{ APIService: a, ctx: ctx, } } // Execute executes the request -// @return []Source -func (a *SourcesAPIService) ListSourcesExecute(r APIListSourcesRequest) ([]Source, *_nethttp.Response, error) { +// @return []Provider +func (a *ProvidersAPIService) ListProvidersExecute(r APIListProvidersRequest) ([]Provider, *_nethttp.Response, error) { var ( localVarHTTPMethod = _nethttp.MethodGet localVarPostBody interface{} localVarFormFileName string localVarFileName string localVarFileBytes []byte - localVarReturnValue []Source + localVarReturnValue []Provider ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "SourcesAPIService.ListSources") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ProvidersAPIService.ListProviders") if err != nil { return localVarReturnValue, nil, GenericOpenAPIError{error: err.Error()} } - localVarPath := localBasePath + "/sources" + localVarPath := localBasePath + "/providers" localVarHeaderParams := make(map[string]string) localVarQueryParams := _neturl.Values{} diff --git a/internal/api/client.go b/internal/api/client.go index 42aa1d49a4..e14afce471 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -57,9 +57,9 @@ type APIClient struct { GroupsAPI *GroupsAPIService - RolesAPI *RolesAPIService + ProvidersAPI *ProvidersAPIService - SourcesAPI *SourcesAPIService + RolesAPI *RolesAPIService TokensAPI *TokensAPIService @@ -88,8 +88,8 @@ func NewAPIClient(cfg *Configuration) *APIClient { c.AuthAPI = (*AuthAPIService)(&c.common) c.DestinationsAPI = (*DestinationsAPIService)(&c.common) c.GroupsAPI = (*GroupsAPIService)(&c.common) + c.ProvidersAPI = (*ProvidersAPIService)(&c.common) c.RolesAPI = (*RolesAPIService)(&c.common) - c.SourcesAPI = (*SourcesAPIService)(&c.common) c.TokensAPI = (*TokensAPIService)(&c.common) c.UsersAPI = (*UsersAPIService)(&c.common) c.VersionAPI = (*VersionAPIService)(&c.common) diff --git a/internal/api/model_group.go b/internal/api/model_group.go index 8771bc431a..df18d4e24b 100644 --- a/internal/api/model_group.go +++ b/internal/api/model_group.go @@ -16,26 +16,26 @@ import ( // Group struct for Group type Group struct { - Id string `json:"id"` - Name string `json:"name"` - Created int64 `json:"created"` - Updated int64 `json:"updated"` - SourceID string `json:"sourceID"` - Users []User `json:"users"` - Roles []Role `json:"roles"` + Id string `json:"id"` + Name string `json:"name"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + ProviderID string `json:"providerID"` + Users []User `json:"users"` + Roles []Role `json:"roles"` } // NewGroup instantiates a new Group object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewGroup(id string, name string, created int64, updated int64, sourceID string, users []User, roles []Role) *Group { +func NewGroup(id string, name string, created int64, updated int64, providerID string, users []User, roles []Role) *Group { this := Group{} this.Id = id this.Name = name this.Created = created this.Updated = updated - this.SourceID = sourceID + this.ProviderID = providerID this.Users = users this.Roles = roles return &this @@ -145,28 +145,28 @@ func (o *Group) SetUpdated(v int64) { o.Updated = v } -// GetSourceID returns the SourceID field value -func (o *Group) GetSourceID() string { +// GetProviderID returns the ProviderID field value +func (o *Group) GetProviderID() string { if o == nil { var ret string return ret } - return o.SourceID + return o.ProviderID } -// GetSourceIDOk returns a tuple with the SourceID field value +// GetProviderIDOk returns a tuple with the ProviderID field value // and a boolean to check if the value has been set. -func (o *Group) GetSourceIDOk() (*string, bool) { +func (o *Group) GetProviderIDOk() (*string, bool) { if o == nil { return nil, false } - return &o.SourceID, true + return &o.ProviderID, true } -// SetSourceID sets field value -func (o *Group) SetSourceID(v string) { - o.SourceID = v +// SetProviderID sets field value +func (o *Group) SetProviderID(v string) { + o.ProviderID = v } // GetUsers returns the Users field value @@ -232,7 +232,7 @@ func (o Group) MarshalJSON() ([]byte, error) { toSerialize["updated"] = o.Updated } if true { - toSerialize["sourceID"] = o.SourceID + toSerialize["providerID"] = o.ProviderID } if true { toSerialize["users"] = o.Users diff --git a/internal/api/model_source.go b/internal/api/model_provider.go similarity index 63% rename from internal/api/model_source.go rename to internal/api/model_provider.go index 82c73f1609..58db2103f1 100644 --- a/internal/api/model_source.go +++ b/internal/api/model_provider.go @@ -14,24 +14,24 @@ import ( "encoding/json" ) -// Source struct for Source -type Source struct { - Id string `json:"id"` - Created int64 `json:"created"` - Updated int64 `json:"updated"` - Domain string `json:"domain" validate:"required"` - ClientID string `json:"clientID" validate:"required"` - ClientSecret string `json:"clientSecret"` - Kind string `json:"kind" validate:"required"` - Okta *SourceOkta `json:"okta,omitempty"` -} - -// NewSource instantiates a new Source object +// Provider struct for Provider +type Provider struct { + Id string `json:"id"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + Domain string `json:"domain" validate:"required"` + ClientID string `json:"clientID" validate:"required"` + ClientSecret string `json:"clientSecret"` + Kind string `json:"kind" validate:"required"` + Okta *ProviderOkta `json:"okta,omitempty"` +} + +// NewProvider instantiates a new Provider object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewSource(id string, created int64, updated int64, domain string, clientID string, clientSecret string, kind string) *Source { - this := Source{} +func NewProvider(id string, created int64, updated int64, domain string, clientID string, clientSecret string, kind string) *Provider { + this := Provider{} this.Id = id this.Created = created this.Updated = updated @@ -42,16 +42,16 @@ func NewSource(id string, created int64, updated int64, domain string, clientID return &this } -// NewSourceWithDefaults instantiates a new Source object +// NewProviderWithDefaults instantiates a new Provider object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewSourceWithDefaults() *Source { - this := Source{} +func NewProviderWithDefaults() *Provider { + this := Provider{} return &this } // GetId returns the Id field value -func (o *Source) GetId() string { +func (o *Provider) GetId() string { if o == nil { var ret string return ret @@ -62,7 +62,7 @@ func (o *Source) GetId() string { // GetIdOk returns a tuple with the Id field value // and a boolean to check if the value has been set. -func (o *Source) GetIdOk() (*string, bool) { +func (o *Provider) GetIdOk() (*string, bool) { if o == nil { return nil, false } @@ -70,12 +70,12 @@ func (o *Source) GetIdOk() (*string, bool) { } // SetId sets field value -func (o *Source) SetId(v string) { +func (o *Provider) SetId(v string) { o.Id = v } // GetCreated returns the Created field value -func (o *Source) GetCreated() int64 { +func (o *Provider) GetCreated() int64 { if o == nil { var ret int64 return ret @@ -86,7 +86,7 @@ func (o *Source) GetCreated() int64 { // GetCreatedOk returns a tuple with the Created field value // and a boolean to check if the value has been set. -func (o *Source) GetCreatedOk() (*int64, bool) { +func (o *Provider) GetCreatedOk() (*int64, bool) { if o == nil { return nil, false } @@ -94,12 +94,12 @@ func (o *Source) GetCreatedOk() (*int64, bool) { } // SetCreated sets field value -func (o *Source) SetCreated(v int64) { +func (o *Provider) SetCreated(v int64) { o.Created = v } // GetUpdated returns the Updated field value -func (o *Source) GetUpdated() int64 { +func (o *Provider) GetUpdated() int64 { if o == nil { var ret int64 return ret @@ -110,7 +110,7 @@ func (o *Source) GetUpdated() int64 { // GetUpdatedOk returns a tuple with the Updated field value // and a boolean to check if the value has been set. -func (o *Source) GetUpdatedOk() (*int64, bool) { +func (o *Provider) GetUpdatedOk() (*int64, bool) { if o == nil { return nil, false } @@ -118,12 +118,12 @@ func (o *Source) GetUpdatedOk() (*int64, bool) { } // SetUpdated sets field value -func (o *Source) SetUpdated(v int64) { +func (o *Provider) SetUpdated(v int64) { o.Updated = v } // GetDomain returns the Domain field value -func (o *Source) GetDomain() string { +func (o *Provider) GetDomain() string { if o == nil { var ret string return ret @@ -134,7 +134,7 @@ func (o *Source) GetDomain() string { // GetDomainOk returns a tuple with the Domain field value // and a boolean to check if the value has been set. -func (o *Source) GetDomainOk() (*string, bool) { +func (o *Provider) GetDomainOk() (*string, bool) { if o == nil { return nil, false } @@ -142,12 +142,12 @@ func (o *Source) GetDomainOk() (*string, bool) { } // SetDomain sets field value -func (o *Source) SetDomain(v string) { +func (o *Provider) SetDomain(v string) { o.Domain = v } // GetClientID returns the ClientID field value -func (o *Source) GetClientID() string { +func (o *Provider) GetClientID() string { if o == nil { var ret string return ret @@ -158,7 +158,7 @@ func (o *Source) GetClientID() string { // GetClientIDOk returns a tuple with the ClientID field value // and a boolean to check if the value has been set. -func (o *Source) GetClientIDOk() (*string, bool) { +func (o *Provider) GetClientIDOk() (*string, bool) { if o == nil { return nil, false } @@ -166,12 +166,12 @@ func (o *Source) GetClientIDOk() (*string, bool) { } // SetClientID sets field value -func (o *Source) SetClientID(v string) { +func (o *Provider) SetClientID(v string) { o.ClientID = v } // GetClientSecret returns the ClientSecret field value -func (o *Source) GetClientSecret() string { +func (o *Provider) GetClientSecret() string { if o == nil { var ret string return ret @@ -182,7 +182,7 @@ func (o *Source) GetClientSecret() string { // GetClientSecretOk returns a tuple with the ClientSecret field value // and a boolean to check if the value has been set. -func (o *Source) GetClientSecretOk() (*string, bool) { +func (o *Provider) GetClientSecretOk() (*string, bool) { if o == nil { return nil, false } @@ -190,12 +190,12 @@ func (o *Source) GetClientSecretOk() (*string, bool) { } // SetClientSecret sets field value -func (o *Source) SetClientSecret(v string) { +func (o *Provider) SetClientSecret(v string) { o.ClientSecret = v } // GetKind returns the Kind field value -func (o *Source) GetKind() string { +func (o *Provider) GetKind() string { if o == nil { var ret string return ret @@ -206,7 +206,7 @@ func (o *Source) GetKind() string { // GetKindOk returns a tuple with the Kind field value // and a boolean to check if the value has been set. -func (o *Source) GetKindOk() (*string, bool) { +func (o *Provider) GetKindOk() (*string, bool) { if o == nil { return nil, false } @@ -214,14 +214,14 @@ func (o *Source) GetKindOk() (*string, bool) { } // SetKind sets field value -func (o *Source) SetKind(v string) { +func (o *Provider) SetKind(v string) { o.Kind = v } // GetOkta returns the Okta field value if set, zero value otherwise. -func (o *Source) GetOkta() SourceOkta { +func (o *Provider) GetOkta() ProviderOkta { if o == nil || o.Okta == nil { - var ret SourceOkta + var ret ProviderOkta return ret } return *o.Okta @@ -229,7 +229,7 @@ func (o *Source) GetOkta() SourceOkta { // GetOktaOk returns a tuple with the Okta field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *Source) GetOktaOk() (*SourceOkta, bool) { +func (o *Provider) GetOktaOk() (*ProviderOkta, bool) { if o == nil || o.Okta == nil { return nil, false } @@ -237,7 +237,7 @@ func (o *Source) GetOktaOk() (*SourceOkta, bool) { } // HasOkta returns a boolean if a field has been set. -func (o *Source) HasOkta() bool { +func (o *Provider) HasOkta() bool { if o != nil && o.Okta != nil { return true } @@ -245,12 +245,12 @@ func (o *Source) HasOkta() bool { return false } -// SetOkta gets a reference to the given SourceOkta and assigns it to the Okta field. -func (o *Source) SetOkta(v SourceOkta) { +// SetOkta gets a reference to the given ProviderOkta and assigns it to the Okta field. +func (o *Provider) SetOkta(v ProviderOkta) { o.Okta = &v } -func (o Source) MarshalJSON() ([]byte, error) { +func (o Provider) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if true { toSerialize["id"] = o.Id @@ -279,38 +279,38 @@ func (o Source) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -type NullableSource struct { - value *Source +type NullableProvider struct { + value *Provider isSet bool } -func (v NullableSource) Get() *Source { +func (v NullableProvider) Get() *Provider { return v.value } -func (v *NullableSource) Set(val *Source) { +func (v *NullableProvider) Set(val *Provider) { v.value = val v.isSet = true } -func (v NullableSource) IsSet() bool { +func (v NullableProvider) IsSet() bool { return v.isSet } -func (v *NullableSource) Unset() { +func (v *NullableProvider) Unset() { v.value = nil v.isSet = false } -func NewNullableSource(val *Source) *NullableSource { - return &NullableSource{value: val, isSet: true} +func NewNullableProvider(val *Provider) *NullableProvider { + return &NullableProvider{value: val, isSet: true} } -func (v NullableSource) MarshalJSON() ([]byte, error) { +func (v NullableProvider) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableSource) UnmarshalJSON(src []byte) error { +func (v *NullableProvider) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/internal/api/model_source_okta.go b/internal/api/model_provider_okta.go similarity index 56% rename from internal/api/model_source_okta.go rename to internal/api/model_provider_okta.go index c39551e6b6..3c0f87d889 100644 --- a/internal/api/model_source_okta.go +++ b/internal/api/model_provider_okta.go @@ -14,31 +14,31 @@ import ( "encoding/json" ) -// SourceOkta struct for SourceOkta -type SourceOkta struct { +// ProviderOkta struct for ProviderOkta +type ProviderOkta struct { APIToken string `json:"apiToken"` } -// NewSourceOkta instantiates a new SourceOkta object +// NewProviderOkta instantiates a new ProviderOkta object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewSourceOkta(apiToken string) *SourceOkta { - this := SourceOkta{} +func NewProviderOkta(apiToken string) *ProviderOkta { + this := ProviderOkta{} this.APIToken = apiToken return &this } -// NewSourceOktaWithDefaults instantiates a new SourceOkta object +// NewProviderOktaWithDefaults instantiates a new ProviderOkta object // This constructor will only assign default values to properties that have it defined, // but it doesn't guarantee that properties required by API are set -func NewSourceOktaWithDefaults() *SourceOkta { - this := SourceOkta{} +func NewProviderOktaWithDefaults() *ProviderOkta { + this := ProviderOkta{} return &this } // GetAPIToken returns the APIToken field value -func (o *SourceOkta) GetAPIToken() string { +func (o *ProviderOkta) GetAPIToken() string { if o == nil { var ret string return ret @@ -49,7 +49,7 @@ func (o *SourceOkta) GetAPIToken() string { // GetAPITokenOk returns a tuple with the APIToken field value // and a boolean to check if the value has been set. -func (o *SourceOkta) GetAPITokenOk() (*string, bool) { +func (o *ProviderOkta) GetAPITokenOk() (*string, bool) { if o == nil { return nil, false } @@ -57,11 +57,11 @@ func (o *SourceOkta) GetAPITokenOk() (*string, bool) { } // SetAPIToken sets field value -func (o *SourceOkta) SetAPIToken(v string) { +func (o *ProviderOkta) SetAPIToken(v string) { o.APIToken = v } -func (o SourceOkta) MarshalJSON() ([]byte, error) { +func (o ProviderOkta) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if true { toSerialize["apiToken"] = o.APIToken @@ -69,38 +69,38 @@ func (o SourceOkta) MarshalJSON() ([]byte, error) { return json.Marshal(toSerialize) } -type NullableSourceOkta struct { - value *SourceOkta +type NullableProviderOkta struct { + value *ProviderOkta isSet bool } -func (v NullableSourceOkta) Get() *SourceOkta { +func (v NullableProviderOkta) Get() *ProviderOkta { return v.value } -func (v *NullableSourceOkta) Set(val *SourceOkta) { +func (v *NullableProviderOkta) Set(val *ProviderOkta) { v.value = val v.isSet = true } -func (v NullableSourceOkta) IsSet() bool { +func (v NullableProviderOkta) IsSet() bool { return v.isSet } -func (v *NullableSourceOkta) Unset() { +func (v *NullableProviderOkta) Unset() { v.value = nil v.isSet = false } -func NewNullableSourceOkta(val *SourceOkta) *NullableSourceOkta { - return &NullableSourceOkta{value: val, isSet: true} +func NewNullableProviderOkta(val *ProviderOkta) *NullableProviderOkta { + return &NullableProviderOkta{value: val, isSet: true} } -func (v NullableSourceOkta) MarshalJSON() ([]byte, error) { +func (v NullableProviderOkta) MarshalJSON() ([]byte, error) { return json.Marshal(v.value) } -func (v *NullableSourceOkta) UnmarshalJSON(src []byte) error { +func (v *NullableProviderOkta) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 8c300ee10d..7b4f23c67f 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -297,7 +297,7 @@ func newStartCmd(globalOptions internal.GlobalOptions) (*cobra.Command, error) { cmd.Flags().String("ui-proxy", "", "proxy UI requests to this host") cmd.Flags().Bool("enable-ui", false, "enable UI") - cmd.Flags().Duration("sources-sync-interval", registry.DefaultSourcesSyncInterval, "the interval at which Infra will poll sources for users and groups") + cmd.Flags().Duration("providers-sync-interval", registry.DefaultProvidersSyncInterval, "the interval at which Infra will poll identity providers for users and groups") cmd.Flags().Duration("destinations-sync-interval", registry.DefaultDestinationsSyncInterval, "the interval at which Infra will poll destinations") cmd.Flags().Bool("enable-telemetry", true, "enable telemetry") diff --git a/internal/cmd/config0dot2.go b/internal/cmd/config.go similarity index 77% rename from internal/cmd/config0dot2.go rename to internal/cmd/config.go index 94f8336da6..5cfbdfd7d3 100644 --- a/internal/cmd/config0dot2.go +++ b/internal/cmd/config.go @@ -8,30 +8,32 @@ import ( "path/filepath" ) -type ClientConfigV0dot2 struct { - Version string `json:"version"` // always 0.2 in v0.2 +// current: v0.3 +type ClientConfig struct { + Version string `json:"version"` Hosts []ClientHostConfig `json:"hosts"` } +// current: v0.3 type ClientHostConfig struct { Name string `json:"name"` Host string `json:"host"` Token string `json:"token"` SkipTLSVerify bool `json:"skip-tls-verify"` // where is the other cert info stored? - SourceID string `json:"source-id"` + ProviderID string `json:"provider-id"` Current bool `json:"current"` } var ErrConfigNotFound = errors.New("could not read local credentials. Are you logged in? Use \"infra login\" to login") -func NewClientConfig() *ClientConfigV0dot2 { - return &ClientConfigV0dot2{ - Version: "0.2", +func NewClientConfig() *ClientConfig { + return &ClientConfig{ + Version: "0.3", } } -func readConfig() (*ClientConfigV0dot2, error) { - config := &ClientConfigV0dot2{} +func readConfig() (*ClientConfig, error) { + config := &ClientConfig{} infraDir, err := infraHomeDir() if err != nil { @@ -58,13 +60,20 @@ func readConfig() (*ClientConfigV0dot2, error) { return nil, err } - return configv0dot1.ToV0dot2(), nil + return configv0dot1.ToV0dot2().ToV0dot3(), nil + } else if config.Version == "0.2" { + configv0dot2 := ClientConfigV0dot2{} + if err = json.Unmarshal(contents, &configv0dot2); err != nil { + return nil, err + } + + return configv0dot2.ToV0dot3(), nil } return config, nil } -func writeConfig(config *ClientConfigV0dot2) error { +func writeConfig(config *ClientConfig) error { infraDir, err := infraHomeDir() if err != nil { return err diff --git a/internal/cmd/config0dot1.go b/internal/cmd/config0dot1.go deleted file mode 100644 index 267ee9224a..0000000000 --- a/internal/cmd/config0dot1.go +++ /dev/null @@ -1,26 +0,0 @@ -package cmd - -type ClientConfigV0dot1 struct { - Version string `json:"version"` // always blank in v0.1 - Name string `json:"name"` - Host string `json:"host"` - Token string `json:"token"` - SkipTLSVerify bool `json:"skip-tls-verify"` - SourceID string `json:"source-id"` -} - -// ToV0dot2 upgrades the config to the 0.2 version -func (c ClientConfigV0dot1) ToV0dot2() *ClientConfigV0dot2 { - return &ClientConfigV0dot2{ - Version: "0.2", - Hosts: []ClientHostConfig{ - { - Name: c.Name, - Host: c.Host, - Token: c.Token, - SkipTLSVerify: c.SkipTLSVerify, - Current: true, - }, - }, - } -} diff --git a/internal/cmd/config_migration.go b/internal/cmd/config_migration.go new file mode 100644 index 0000000000..e4cf517554 --- /dev/null +++ b/internal/cmd/config_migration.go @@ -0,0 +1,60 @@ +package cmd + +type ClientConfigV0dot1 struct { + Version string `json:"version"` // always blank in v0.1 + Name string `json:"name"` + Host string `json:"host"` + Token string `json:"token"` + SkipTLSVerify bool `json:"skip-tls-verify"` + SourceID string `json:"source-id"` +} + +type ClientConfigV0dot2 struct { + Version string `json:"version"` // v0.2 + Hosts []ClientHostConfigV0dot2 `json:"hosts"` +} + +type ClientHostConfigV0dot2 struct { + Name string `json:"name"` + Host string `json:"host"` + Token string `json:"token"` + SkipTLSVerify bool `json:"skip-tls-verify"` + SourceID string `json:"source-id"` + Current bool `json:"current"` +} + +// ToV0dot2 upgrades the config to the 0.2 version +func (c ClientConfigV0dot1) ToV0dot2() *ClientConfigV0dot2 { + return &ClientConfigV0dot2{ + Version: "0.2", + Hosts: []ClientHostConfigV0dot2{ + { + Name: c.Name, + Host: c.Host, + Token: c.Token, + SkipTLSVerify: c.SkipTLSVerify, + Current: true, + }, + }, + } +} + +// ToV0dot3 upgrades the config to the 0.3 version +func (c ClientConfigV0dot2) ToV0dot3() *ClientConfig { + conf := &ClientConfig{ + Version: "0.3", + } + + for _, h := range c.Hosts { + conf.Hosts = append(conf.Hosts, ClientHostConfig{ + Name: h.Name, + Host: h.Host, + Token: h.Token, + SkipTLSVerify: h.SkipTLSVerify, + ProviderID: h.SourceID, + Current: h.Current, + }) + } + + return conf +} diff --git a/internal/cmd/login.go b/internal/cmd/login.go index 4cc4a533e2..5cec616a59 100644 --- a/internal/cmd/login.go +++ b/internal/cmd/login.go @@ -106,31 +106,31 @@ host: return err } - sources, res, err := client.SourcesAPI.ListSources(context.Background()).Execute() + providers, res, err := client.ProvidersAPI.ListProviders(context.Background()).Execute() if err != nil { return errWithResponseContext(err, res) } - var selectedSource *api.Source + var selectedProvider *api.Provider -source: +provider: switch { - case len(sources) == 0: + case len(providers) == 0: return errors.New("no identity providers have been configured") - case len(sources) == 1: - selectedSource = &sources[0] + case len(providers) == 1: + selectedProvider = &providers[0] default: - // Use the current source ID if it's valid to avoid prompting the user - if selectedHost.SourceID != "" && options.Current { - for i, source := range sources { - if source.Id == selectedHost.SourceID { - selectedSource = &sources[i] - break source + // Use the current provider ID if it's valid to avoid prompting the user + if selectedHost.ProviderID != "" && options.Current { + for i, provider := range providers { + if provider.Id == selectedHost.ProviderID { + selectedProvider = &providers[i] + break provider } } } - selectedSource, err = promptSelectSource(sources) + selectedProvider, err = promptSelectProvider(providers) if errors.Is(err, terminal.InterruptErr) { return nil } @@ -143,7 +143,7 @@ source: var loginReq api.LoginRequest switch { - case selectedSource.Okta != nil: + case selectedProvider.Okta != nil: // Start OIDC flow // Get auth code from Okta // Send auth code to Infra to login as a user @@ -157,7 +157,7 @@ source: return err } - authorizeURL := "https://" + selectedSource.Domain + "/oauth2/v1/authorize?redirect_uri=" + "http://localhost:8301&client_id=" + selectedSource.ClientID + "&response_type=code&scope=openid+email&nonce=" + nonce + "&state=" + state + authorizeURL := "https://" + selectedProvider.Domain + "/oauth2/v1/authorize?redirect_uri=" + "http://localhost:8301&client_id=" + selectedProvider.ClientID + "&response_type=code&scope=openid+email&nonce=" + nonce + "&state=" + state fmt.Fprintf(os.Stderr, "%s Logging in with %s...\n", blue("✓"), termenv.String("Okta").Bold().String()) @@ -181,11 +181,11 @@ source: } loginReq.Okta = &api.LoginRequestOkta{ - Domain: selectedSource.Domain, + Domain: selectedProvider.Domain, Code: code, } default: - return errors.New("invalid source selected") + return errors.New("invalid provider selected") } loginRes, res, err := client.AuthAPI.Login(context.Background()).Body(loginReq).Execute() @@ -200,7 +200,7 @@ source: selectedHost.Name = loginRes.Name selectedHost.Token = loginRes.Token selectedHost.SkipTLSVerify = skipTLSVerify - selectedHost.SourceID = selectedSource.Id + selectedHost.ProviderID = selectedProvider.Id selectedHost.Current = true err = writeConfig(loadedCfg) @@ -324,20 +324,20 @@ func promptShouldSkipTLSVerify(host string) (shouldSkipTLSVerify bool, proceed b return false, true, nil } -func promptSelectSource(sources []api.Source) (*api.Source, error) { - if sources == nil { - return nil, errors.New("sources cannot be nil") +func promptSelectProvider(providers []api.Provider) (*api.Provider, error) { + if providers == nil { + return nil, errors.New("providers cannot be nil") } - sort.Slice(sources, func(i, j int) bool { - return sources[i].Created > sources[j].Created + sort.Slice(providers, func(i, j int) bool { + return providers[i].Created > providers[j].Created }) options := []string{} - for _, s := range sources { - if s.Okta != nil { - options = append(options, fmt.Sprintf("Okta [%s]", s.Domain)) + for _, p := range providers { + if p.Okta != nil { + options = append(options, fmt.Sprintf("Okta [%s]", p.Domain)) } } @@ -355,7 +355,7 @@ func promptSelectSource(sources []api.Source) (*api.Source, error) { return nil, err } - return &sources[option], nil + return &providers[option], nil } func switchToFirstInfraContext() (string, error) { diff --git a/internal/registry/_testdata/infra.yaml b/internal/registry/_testdata/infra.yaml index f11948ab98..57bbf17d9d 100644 --- a/internal/registry/_testdata/infra.yaml +++ b/internal/registry/_testdata/infra.yaml @@ -3,23 +3,21 @@ secrets: kind: plaintext base64: true -sources: +providers: - kind: okta domain: overwrite.example.com - client-id: base64:MG9hcG4wcXdpUVBpTUl5UjM1ZDY= - client-secret: kubernetes:okta-secrets/clientSecret - okta: - api-token: kubernetes:okta-secrets/apiToken + clientID: base64:MG9hcG4wcXdpUVBpTUl5UjM1ZDY= + clientSecret: kubernetes:okta-secrets/clientSecret + apiToken: kubernetes:okta-secrets/apiToken - kind: okta domain: https://test.example.com - client-id: plaintext:0oapn0qwiQPiMIyR35d6 - client-secret: kubernetes:okta-secrets/clientSecret - okta: - api-token: kubernetes:okta-secrets/apiToken + clientID: plaintext:0oapn0qwiQPiMIyR35d6 + clientSecret: kubernetes:okta-secrets/clientSecret + apiToken: kubernetes:okta-secrets/apiToken groups: - name: ios-developers - source: okta + provider: okta roles: - name: writer kind: cluster-role @@ -39,28 +37,28 @@ groups: namespaces: - infrahq - name: mac-admins - source: okta + provider: okta roles: - name: writer kind: cluster-role destinations: - name: cluster-BBB - name: adversaries - source: outside + provider: outside roles: - name: cluster-admin kind: cluster-role destinations: - name: cluster-AAA - name: heroes - source: okta + provider: okta roles: - name: writer kind: cluster-role destinations: - name: cluster-CCC - name: villains - source: okta + provider: okta roles: - name: writer kind: cluster-role diff --git a/internal/registry/api.go b/internal/registry/api.go index 1fbf85eaad..2b1eafcc4a 100644 --- a/internal/registry/api.go +++ b/internal/registry/api.go @@ -56,8 +56,8 @@ func NewAPIMux(reg *Registry) *mux.Router { v1.Handle("/groups", a.bearerAuthMiddleware(api.GROUPS_READ, http.HandlerFunc(a.ListGroups))).Methods(http.MethodGet) v1.Handle("/groups/{id}", a.bearerAuthMiddleware(api.GROUPS_READ, http.HandlerFunc(a.GetGroup))).Methods(http.MethodGet) - v1.Handle("/sources", http.HandlerFunc(a.ListSources)).Methods(http.MethodGet) - v1.Handle("/sources/{id}", http.HandlerFunc(a.GetSource)).Methods(http.MethodGet) + v1.Handle("/providers", http.HandlerFunc(a.ListProviders)).Methods(http.MethodGet) + v1.Handle("/providers/{id}", http.HandlerFunc(a.GetProvider)).Methods(http.MethodGet) v1.Handle("/destinations", a.bearerAuthMiddleware(api.DESTINATIONS_READ, http.HandlerFunc(a.ListDestinations))).Methods(http.MethodGet) v1.Handle("/destinations", a.bearerAuthMiddleware(api.DESTINATIONS_CREATE, http.HandlerFunc(a.CreateDestination))).Methods(http.MethodPost) @@ -322,60 +322,60 @@ func (a *API) GetGroup(w http.ResponseWriter, r *http.Request) { } } -func (a *API) ListSources(w http.ResponseWriter, r *http.Request) { - sourceKind := r.URL.Query().Get("kind") +func (a *API) ListProviders(w http.ResponseWriter, r *http.Request) { + providerKind := r.URL.Query().Get("kind") - var sources []Source - if err := a.db.Find(&sources, &Source{Kind: sourceKind}).Error; err != nil { + var providers []Provider + if err := a.db.Find(&providers, &Provider{Kind: providerKind}).Error; err != nil { logging.L.Error(err.Error()) - sendAPIError(w, http.StatusInternalServerError, "could not list sources") + sendAPIError(w, http.StatusInternalServerError, "could not list providers") return } - results := make([]api.Source, 0) - for _, s := range sources { - results = append(results, s.marshal()) + results := make([]api.Provider, 0) + for _, p := range providers { + results = append(results, p.marshal()) } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(results); err != nil { logging.L.Error(err.Error()) - sendAPIError(w, http.StatusInternalServerError, "could not list sources") + sendAPIError(w, http.StatusInternalServerError, "could not list providers") } } -func (a *API) GetSource(w http.ResponseWriter, r *http.Request) { +func (a *API) GetProvider(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - sourceId := vars["id"] - if sourceId == "" { + providerId := vars["id"] + if providerId == "" { sendAPIError(w, http.StatusBadRequest, "Path parameter \"id\" is required") return } - var source Source - if err := a.db.First(&source, &Source{Id: sourceId}).Error; err != nil { + var provider Provider + if err := a.db.First(&provider, &Provider{Id: providerId}).Error; err != nil { logging.L.Error(err.Error()) if errors.Is(err, gorm.ErrRecordNotFound) { - sendAPIError(w, http.StatusNotFound, fmt.Sprintf("Could not find source ID \"%s\"", sourceId)) + sendAPIError(w, http.StatusNotFound, fmt.Sprintf("Could not find provider ID \"%s\"", providerId)) } else { - sendAPIError(w, http.StatusBadRequest, fmt.Sprintf("Could not find source ID \"%s\"", sourceId)) + sendAPIError(w, http.StatusBadRequest, fmt.Sprintf("Could not find provider ID \"%s\"", providerId)) } return } - result := source.marshal() + result := provider.marshal() w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(result); err != nil { logging.L.Error(err.Error()) - sendAPIError(w, http.StatusInternalServerError, "could not list sources") + sendAPIError(w, http.StatusInternalServerError, "could not list providers") } } @@ -788,15 +788,15 @@ func (a *API) Login(w http.ResponseWriter, r *http.Request) { switch { case body.Okta != nil: - var source Source - if err := a.db.Where(&Source{Kind: SourceKindOkta, Domain: body.Okta.Domain}).First(&source).Error; err != nil { - logging.L.Debug("Could not retrieve okta source from db: " + err.Error()) + var provider Provider + if err := a.db.Where(&Provider{Kind: ProviderKindOkta, Domain: body.Okta.Domain}).First(&provider).Error; err != nil { + logging.L.Debug("Could not retrieve okta provider from db: " + err.Error()) sendAPIError(w, http.StatusBadRequest, "invalid okta login information") return } - clientSecret, err := a.registry.GetSecret(source.ClientSecret) + clientSecret, err := a.registry.GetSecret(provider.ClientSecret) if err != nil { logging.L.Error("Could not retrieve okta client secret from provider: " + err.Error()) sendAPIError(w, http.StatusInternalServerError, "invalid okta login information") @@ -806,8 +806,8 @@ func (a *API) Login(w http.ResponseWriter, r *http.Request) { email, err := a.okta.EmailFromCode( body.Okta.Code, - source.Domain, - source.ClientID, + provider.Domain, + provider.ClientID, clientSecret, ) if err != nil { @@ -887,8 +887,8 @@ func (a *API) Version(w http.ResponseWriter, r *http.Request) { } } -func (s *Source) marshal() api.Source { - res := api.Source{ +func (s *Provider) marshal() api.Provider { + res := api.Provider{ Id: s.Id, Created: s.Created, Updated: s.Updated, @@ -898,8 +898,8 @@ func (s *Source) marshal() api.Source { Kind: s.Kind, } - if s.Kind == SourceKindOkta { - res.Okta = &api.SourceOkta{ + if s.Kind == ProviderKindOkta { + res.Okta = &api.ProviderOkta{ APIToken: s.APIToken, } } @@ -1016,11 +1016,11 @@ func (u *User) marshal() api.User { func (g *Group) marshal() api.Group { res := api.Group{ - Id: g.Id, - Created: g.Created, - Updated: g.Updated, - Name: g.Name, - SourceID: g.SourceId, + Id: g.Id, + Created: g.Created, + Updated: g.Updated, + Name: g.Name, + ProviderID: g.ProviderId, } for _, u := range g.Users { diff --git a/internal/registry/api_test.go b/internal/registry/api_test.go index 75584f5a60..f2c68e1226 100644 --- a/internal/registry/api_test.go +++ b/internal/registry/api_test.go @@ -668,19 +668,19 @@ func TestLoginMethodOkta(t *testing.T) { t.Fatal(err) } - var source Source - source.Kind = SourceKindOkta - source.APIToken = "test-api-token/apiToken" - source.Domain = "test.okta.com" - source.ClientID = "test-client-id" - source.ClientSecret = "test-client-secret/clientSecret" - - if err := db.Create(&source).Error; err != nil { + var provider Provider + provider.Kind = ProviderKindOkta + provider.APIToken = "test-api-token/apiToken" + provider.Domain = "test.okta.com" + provider.ClientID = "test-client-id" + provider.ClientSecret = "test-client-secret/clientSecret" + + if err := db.Create(&provider).Error; err != nil { t.Fatal(err) } var user User - if err := source.CreateUser(db, &user, "test@test.com"); err != nil { + if err := provider.CreateUser(db, &user, "test@test.com"); err != nil { t.Fatal(err) } @@ -1401,7 +1401,7 @@ func TestGetUserNotFound(t *testing.T) { assert.Equal(t, http.StatusNotFound, w.Code) } -func TestListSources(t *testing.T) { +func TestListProviders(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1412,21 +1412,21 @@ func TestListSources(t *testing.T) { db: db, } - r := httptest.NewRequest(http.MethodGet, "/v1/sources", nil) + r := httptest.NewRequest(http.MethodGet, "/v1/providers", nil) w := httptest.NewRecorder() - http.HandlerFunc(a.ListSources).ServeHTTP(w, r) + http.HandlerFunc(a.ListProviders).ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Code) - var sources []api.Source - if err := json.NewDecoder(w.Body).Decode(&sources); err != nil { + var providers []api.Provider + if err := json.NewDecoder(w.Body).Decode(&providers); err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(sources)) + assert.Equal(t, 1, len(providers)) } -func TestListSourcesByType(t *testing.T) { +func TestListProvidersByType(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1437,21 +1437,21 @@ func TestListSourcesByType(t *testing.T) { db: db, } - r := httptest.NewRequest(http.MethodGet, "/v1/sources?kind=okta", nil) + r := httptest.NewRequest(http.MethodGet, "/v1/providers?kind=okta", nil) w := httptest.NewRecorder() - http.HandlerFunc(a.ListSources).ServeHTTP(w, r) + http.HandlerFunc(a.ListProviders).ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Code) - var sources []api.Source - if err := json.NewDecoder(w.Body).Decode(&sources); err != nil { + var providers []api.Provider + if err := json.NewDecoder(w.Body).Decode(&providers); err != nil { t.Fatal(err) } - assert.Equal(t, 1, len(sources)) + assert.Equal(t, 1, len(providers)) } -func TestListSourcesEmpty(t *testing.T) { +func TestListProvidersEmpty(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1462,21 +1462,21 @@ func TestListSourcesEmpty(t *testing.T) { db: db, } - r := httptest.NewRequest(http.MethodGet, "/v1/sources?kind=nonexistent", nil) + r := httptest.NewRequest(http.MethodGet, "/v1/providers?kind=nonexistent", nil) w := httptest.NewRecorder() - http.HandlerFunc(a.ListSources).ServeHTTP(w, r) + http.HandlerFunc(a.ListProviders).ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Code) - var sources []api.Source - if err := json.NewDecoder(w.Body).Decode(&sources); err != nil { + var providers []api.Provider + if err := json.NewDecoder(w.Body).Decode(&providers); err != nil { t.Fatal(err) } - assert.Equal(t, 0, len(sources)) + assert.Equal(t, 0, len(providers)) } -func TestGetSource(t *testing.T) { +func TestGetProvider(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1487,26 +1487,26 @@ func TestGetSource(t *testing.T) { db: db, } - source := &Source{Kind: SourceKindOkta} - if err := a.db.Create(source).Error; err != nil { + provider := &Provider{Kind: ProviderKindOkta} + if err := a.db.Create(provider).Error; err != nil { t.Fatalf(err.Error()) } - defer a.db.Delete(source) + defer a.db.Delete(provider) - r := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sources/%s", source.Id), nil) + r := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/v1/providers/%s", provider.Id), nil) vars := map[string]string{ - "id": source.Id, + "id": provider.Id, } r = mux.SetURLVars(r, vars) w := httptest.NewRecorder() - http.HandlerFunc(a.GetSource).ServeHTTP(w, r) + http.HandlerFunc(a.GetProvider).ServeHTTP(w, r) assert.Equal(t, http.StatusOK, w.Code) } -func TestGetSourceEmptyID(t *testing.T) { +func TestGetProviderEmptyID(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1517,19 +1517,19 @@ func TestGetSourceEmptyID(t *testing.T) { db: db, } - r := httptest.NewRequest(http.MethodGet, "/v1/sources/", nil) + r := httptest.NewRequest(http.MethodGet, "/v1/providers/", nil) vars := map[string]string{ "id": "", } r = mux.SetURLVars(r, vars) w := httptest.NewRecorder() - http.HandlerFunc(a.GetSource).ServeHTTP(w, r) + http.HandlerFunc(a.GetProvider).ServeHTTP(w, r) assert.Equal(t, http.StatusBadRequest, w.Code) } -func TestGetSourceNotFound(t *testing.T) { +func TestGetProviderNotFound(t *testing.T) { a := &API{ registry: &Registry{ db: db, @@ -1540,14 +1540,14 @@ func TestGetSourceNotFound(t *testing.T) { db: db, } - r := httptest.NewRequest(http.MethodGet, "/v1/sources/nonexistent", nil) + r := httptest.NewRequest(http.MethodGet, "/v1/providers/nonexistent", nil) vars := map[string]string{ "id": "nonexistent", } r = mux.SetURLVars(r, vars) w := httptest.NewRecorder() - http.HandlerFunc(a.GetSource).ServeHTTP(w, r) + http.HandlerFunc(a.GetProvider).ServeHTTP(w, r) assert.Equal(t, http.StatusNotFound, w.Code) } diff --git a/internal/registry/config.go b/internal/registry/config.go index 6b08636650..6ddb68db45 100644 --- a/internal/registry/config.go +++ b/internal/registry/config.go @@ -14,15 +14,51 @@ import ( ) type ConfigOkta struct { - APIToken string `yaml:"api-token"` + APIToken string `yaml:"apiToken"` } -type ConfigSource struct { - Kind string `yaml:"kind"` - Domain string `yaml:"domain"` - ClientID string `yaml:"client-id"` - ClientSecret string `yaml:"client-secret"` - Okta ConfigOkta `yaml:"okta"` +type ConfigIdentityProvider struct { + Kind string `yaml:"kind"` + Domain string `yaml:"domain"` + ClientID string `yaml:"clientID"` + ClientSecret string `yaml:"clientSecret"` + Config interface{} // contains identity-provider-specific config +} + +type baseConfigIdentityProvider struct { + Kind string `yaml:"kind"` + Domain string `yaml:"domain"` + ClientID string `yaml:"clientID"` + ClientSecret string `yaml:"clientSecret"` +} + +var _ yaml.Unmarshaler = &ConfigIdentityProvider{} + +func (idp *ConfigIdentityProvider) UnmarshalYAML(unmarshal func(interface{}) error) error { + tmp := &baseConfigIdentityProvider{} + + if err := unmarshal(&tmp); err != nil { + return fmt.Errorf("unmarshalling secret provider: %w", err) + } + + idp.Kind = tmp.Kind + idp.Domain = tmp.Domain + idp.ClientID = tmp.ClientID + idp.ClientSecret = tmp.ClientSecret + + switch tmp.Kind { + case ProviderKindOkta: + o := ConfigOkta{} + if err := unmarshal(&o); err != nil { + return fmt.Errorf("unmarshal yaml: %w", err) + } + + idp.Config = o + default: + return fmt.Errorf("unknown identity provider type %q, expected %s", tmp.Kind, ProviderKindOkta) + } + + return nil } var ( @@ -30,10 +66,10 @@ var ( protocolRemover = regexp.MustCompile(`http[s]?://`) ) -func (s *ConfigSource) cleanupDomain() { - s.Domain = strings.TrimSpace(s.Domain) - s.Domain = dashAdminRemover.ReplaceAllString(s.Domain, "$1$2") - s.Domain = protocolRemover.ReplaceAllString(s.Domain, "") +func (p *ConfigIdentityProvider) cleanupDomain() { + p.Domain = strings.TrimSpace(p.Domain) + p.Domain = dashAdminRemover.ReplaceAllString(p.Domain, "$1$2") + p.Domain = protocolRemover.ReplaceAllString(p.Domain, "") } type ConfigDestination struct { @@ -48,9 +84,9 @@ type ConfigRoleKubernetes struct { } type ConfigGroupMapping struct { - Name string `yaml:"name"` - Source string `yaml:"source"` - Roles []ConfigRoleKubernetes `yaml:"roles"` + Name string `yaml:"name"` + Provider string `yaml:"provider"` + Roles []ConfigRoleKubernetes `yaml:"roles"` } type ConfigUserMapping struct { @@ -153,104 +189,110 @@ func (sp *ConfigSecretProvider) UnmarshalYAML(unmarshal func(interface{}) error) } type Config struct { - Secrets []ConfigSecretProvider `yaml:"secrets"` - Sources []ConfigSource `yaml:"sources"` - Groups []ConfigGroupMapping `yaml:"groups"` - Users []ConfigUserMapping `yaml:"users"` + Secrets []ConfigSecretProvider `yaml:"secrets"` + Providers []ConfigIdentityProvider `yaml:"providers"` + Groups []ConfigGroupMapping `yaml:"groups"` + Users []ConfigUserMapping `yaml:"users"` } // this config is loaded at start-up and re-applied when Infra's state changes (ie. a user is added) var initialConfig Config -func ImportSources(db *gorm.DB, sources []ConfigSource) error { +func ImportProviders(db *gorm.DB, providers []ConfigIdentityProvider) error { var idsToKeep []string - for _, s := range sources { - switch s.Kind { - case SourceKindOkta: - // check the domain is specified - s.cleanupDomain() - - if s.Domain == "" { - logging.S.Infof("domain not set on source \"%s\", import skipped", s.Kind) + for _, p := range providers { + // check if we are about to override an existing provider + var existing Provider + if err := db.First(&existing, &Provider{Kind: p.Kind}).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + // expected for new records + } else { + return fmt.Errorf("existing provider lookup: %w", err) } + } - // check if we are about to override an existing source - var existing Source + if existing.Id != "" { + logging.L.Warn("overriding existing okta provider settings with configuration settings") + } - db.First(&existing, &Source{Kind: SourceKindOkta}) + p.cleanupDomain() - if existing.Id != "" { - logging.L.Warn("overriding existing okta source settings with configuration settings") - } + if p.Domain == "" { + return fmt.Errorf("no domain set on provider: %s", p.Kind) + } - var source Source - if err := db.FirstOrCreate(&source, &Source{Kind: SourceKindOkta}).Error; err != nil { - return fmt.Errorf("create config source: %w", err) - } + if p.ClientID == "" { + return fmt.Errorf("no clientID set on provider: %s", p.Kind) + } - if s.ClientID == "" { - logging.L.Warn("importing okta source with no client ID set") - } + if p.ClientSecret == "" { + return fmt.Errorf("no clientSecret set on provider: %s", p.Kind) + } - if s.Domain == "" { - logging.L.Warn("importing okta source with no domain set") - } + var provider Provider + if err := db.FirstOrCreate(&provider, &Provider{Kind: p.Kind}).Error; err != nil { + return fmt.Errorf("create config provider: %w", err) + } - if s.ClientSecret == "" { - logging.L.Warn("importing okta source with no client secret set") + provider.ClientID = p.ClientID + provider.Domain = p.Domain + provider.ClientSecret = p.ClientSecret + + switch p.Kind { + case ProviderKindOkta: + cfg, ok := p.Config.(ConfigOkta) + if !ok { + return fmt.Errorf("expected provider config to be Okta, but was %t", p.Config) } - if s.Okta.APIToken == "" { - logging.L.Warn("importing okta source with no API token set") + if cfg.APIToken == "" { + return fmt.Errorf("no apiToken set on provider: %s", p.Kind) } - source.ClientID = s.ClientID - source.Domain = s.Domain // API token and client secret will be validated to exist when they are used - source.ClientSecret = s.ClientSecret - source.APIToken = s.Okta.APIToken + provider.APIToken = cfg.APIToken - if err := db.Save(&source).Error; err != nil { - return fmt.Errorf("save source: %w", err) + if err := db.Save(&provider).Error; err != nil { + return fmt.Errorf("save provider: %w", err) } - idsToKeep = append(idsToKeep, source.Id) + idsToKeep = append(idsToKeep, provider.Id) case "": - logging.S.Errorf("skipping a source with no kind set in configuration") + logging.S.Errorf("skipping a provider with no kind set in configuration") default: - logging.S.Errorf("skipping invalid source kind in configuration: %s", s.Kind) + logging.S.Errorf("skipping invalid provider kind in configuration: %s", p.Kind) } } if len(idsToKeep) == 0 { - logging.L.Debug("no valid sources found in configuration, ensure the required fields are specified correctly") - // clear the sources - return db.Where("1 = 1").Delete(&Source{}).Error + logging.L.Debug("no valid providers found in configuration, ensure the required fields are specified correctly") + // clear the providers + return db.Where("1 = 1").Delete(&Provider{}).Error } - return db.Not(idsToKeep).Delete(&Source{}).Error + return db.Not(idsToKeep).Delete(&Provider{}).Error } func ApplyGroupMappings(db *gorm.DB, groups []ConfigGroupMapping) (modifiedRoleIDs []string, err error) { for _, g := range groups { - // get the source from the datastore that this group specifies - var source Source - // Assumes that only one kind of each source can exist - srcReadErr := db.Where(&Source{Kind: g.Source}).First(&source).Error - if srcReadErr != nil { - if errors.Is(srcReadErr, gorm.ErrRecordNotFound) { - // skip this source, it will need to be added in the config and re-applied - logging.S.Debugf("skipping group '%s' with source '%s' in config that does not exist", g.Name, g.Source) + // get the provider from the datastore that this group specifies + var provider Provider + // Assumes that only one kind of each provider can exist + provReadErr := db.Where(&Provider{Kind: g.Provider}).First(&provider).Error + if provReadErr != nil { + if errors.Is(provReadErr, gorm.ErrRecordNotFound) { + // skip this provider, it will need to be added in the config and re-applied + logging.S.Debugf("skipping group '%s' with provider '%s' in config that does not exist", g.Name, g.Provider) continue } - return nil, fmt.Errorf("group read source: %w", srcReadErr) + return nil, fmt.Errorf("group read provider: %w", provReadErr) } var group Group - grpReadErr := db.Preload("Users").Where(&Group{Name: g.Name, SourceId: source.Id}).First(&group).Error + grpReadErr := db.Preload("Users").Where(&Group{Name: g.Name, ProviderId: provider.Id}).First(&group).Error if grpReadErr != nil { if errors.Is(grpReadErr, gorm.ErrRecordNotFound) { // skip this group, if they're created these roles will be added later @@ -373,7 +415,7 @@ func (r *Registry) importConfig(bs []byte) error { } return r.db.Transaction(func(tx *gorm.DB) error { - if err := ImportSources(tx, config.Sources); err != nil { + if err := ImportProviders(tx, config.Providers); err != nil { return err } @@ -422,7 +464,7 @@ func importRoles(db *gorm.DB, roles []ConfigRoleKubernetes) (rolesImported []Rol for _, namespace := range destination.Namespaces { var role Role if err = db.FirstOrCreate(&role, &Role{Name: r.Name, Kind: r.Kind, Namespace: namespace, DestinationId: dest.Id}).Error; err != nil { - return nil, nil, fmt.Errorf("group read source: %w", err) + return nil, nil, fmt.Errorf("group read provider: %w", err) } rolesImported = append(rolesImported, role) diff --git a/internal/registry/config_test.go b/internal/registry/config_test.go index fd328b4c51..ed384b079b 100644 --- a/internal/registry/config_test.go +++ b/internal/registry/config_test.go @@ -15,16 +15,16 @@ import ( var db *gorm.DB var ( - fakeOktaSource = Source{Id: "001", Kind: SourceKindOkta, Domain: "test.example.com", ClientSecret: "kubernetes:okta-secrets/client-secret", APIToken: "kubernetes:okta-secrets/api-token"} - adminUser = User{Id: "001", Email: "admin@example.com"} - standardUser = User{Id: "002", Email: "user@example.com"} - iosDevUser = User{Id: "003", Email: "woz@example.com"} - iosDevGroup = Group{Name: "ios-developers", SourceId: fakeOktaSource.Id} - macAdminGroup = Group{Name: "mac-admins", SourceId: fakeOktaSource.Id} - notInConfigRole = Role{Name: "does-not-exist"} - clusterA = Destination{Name: "cluster-AAA"} - clusterB = Destination{Name: "cluster-BBB"} - clusterC = Destination{Name: "cluster-CCC"} + fakeOktaProvider = Provider{Id: "001", Kind: ProviderKindOkta, Domain: "test.example.com", ClientSecret: "kubernetes:okta-secrets/apiToken", APIToken: "kubernetes:okta-secrets/apiToken"} + adminUser = User{Id: "001", Email: "admin@example.com"} + standardUser = User{Id: "002", Email: "user@example.com"} + iosDevUser = User{Id: "003", Email: "woz@example.com"} + iosDevGroup = Group{Name: "ios-developers", ProviderId: fakeOktaProvider.Id} + macAdminGroup = Group{Name: "mac-admins", ProviderId: fakeOktaProvider.Id} + notInConfigRole = Role{Name: "does-not-exist"} + clusterA = Destination{Name: "cluster-AAA"} + clusterB = Destination{Name: "cluster-BBB"} + clusterC = Destination{Name: "cluster-CCC"} registry *Registry ) @@ -40,7 +40,7 @@ func setup() error { return err } - err = db.Create(&fakeOktaSource).Error + err = db.Create(&fakeOktaProvider).Error if err != nil { return err } @@ -50,7 +50,7 @@ func setup() error { return err } - err = db.Model(&fakeOktaSource).Association("Users").Append(&adminUser) + err = db.Model(&fakeOktaProvider).Association("Users").Append(&adminUser) if err != nil { return err } @@ -60,7 +60,7 @@ func setup() error { return err } - err = db.Model(&fakeOktaSource).Association("Users").Append(&standardUser) + err = db.Model(&fakeOktaProvider).Association("Users").Append(&standardUser) if err != nil { return err } @@ -70,7 +70,7 @@ func setup() error { return err } - err = db.Model(&fakeOktaSource).Association("Users").Append(&iosDevUser) + err = db.Model(&fakeOktaProvider).Association("Users").Append(&iosDevUser) if err != nil { return err } @@ -170,14 +170,14 @@ func TestImportRemovesUnusedRoles(t *testing.T) { assert.ErrorIs(t, err, gorm.ErrRecordNotFound) } -func TestExistingSourceIsOverridden(t *testing.T) { - // this source comes second in the config so it will override the one before it - var importedOkta Source - if err := db.Where(&Source{Kind: SourceKindOkta}).First(&importedOkta).Error; err != nil { +func TestExistingProviderIsOverridden(t *testing.T) { + // this provider comes second in the config so it will override the one before it + var importedOkta Provider + if err := db.Where(&Provider{Kind: ProviderKindOkta}).First(&importedOkta).Error; err != nil { t.Fatal(err) } - assert.Equal(t, fakeOktaSource.Domain, importedOkta.Domain) + assert.Equal(t, fakeOktaProvider.Domain, importedOkta.Domain) } func TestClusterRolesAreAppliedToGroup(t *testing.T) { @@ -291,11 +291,11 @@ func TestClusterRolesAreAppliedWithNamespacesToUsers(t *testing.T) { } func TestCleanupDomain(t *testing.T) { - s := ConfigSource{Domain: "dev123123-admin.okta.com "} - s.cleanupDomain() + p := ConfigIdentityProvider{Domain: "dev123123-admin.okta.com "} + p.cleanupDomain() expected := "dev123123.okta.com" - require.Equal(t, expected, s.Domain) + require.Equal(t, expected, p.Domain) } func containsUserRoleForDestination(db *gorm.DB, user User, destinationId string, roleName string) (bool, error) { @@ -340,8 +340,8 @@ func TestSecretsLoadedOkay(t *testing.T) { require.NoError(t, err) require.Equal(t, "foo", string(foo)) - var importedOkta Source - err = db.Where(&Source{Kind: SourceKindOkta}).First(&importedOkta).Error + var importedOkta Provider + err = db.Where(&Provider{Kind: ProviderKindOkta}).First(&importedOkta).Error require.NoError(t, err) // simple manual secret reader diff --git a/internal/registry/data.go b/internal/registry/data.go index c3b90bb33e..ea5809e7ab 100644 --- a/internal/registry/data.go +++ b/internal/registry/data.go @@ -31,14 +31,14 @@ type User struct { Updated int64 `gorm:"autoUpdateTime"` Email string `gorm:"unique"` - Sources []Source `gorm:"many2many:users_sources"` - Roles []Role `gorm:"many2many:users_roles"` - Groups []Group `gorm:"many2many:groups_users"` + Providers []Provider `gorm:"many2many:users_providers"` + Roles []Role `gorm:"many2many:users_roles"` + Groups []Group `gorm:"many2many:groups_users"` } -var SourceKindOkta = "okta" +var ProviderKindOkta = "okta" -type Source struct { +type Provider struct { Id string `gorm:"primaryKey"` Created int64 `gorm:"autoCreateTime"` Updated int64 `gorm:"autoUpdateTime"` @@ -51,16 +51,16 @@ type Source struct { // used for okta sync APIToken string - Users []User `gorm:"many2many:users_sources"` + Users []User `gorm:"many2many:users_providers"` } type Group struct { - Id string `gorm:"primaryKey"` - Created int64 `gorm:"autoCreateTime"` - Updated int64 `gorm:"autoUpdateTime"` - Name string - SourceId string - Source Source `gorm:"foreignKey:SourceId;references:Id"` + Id string `gorm:"primaryKey"` + Created int64 `gorm:"autoCreateTime"` + Updated int64 `gorm:"autoUpdateTime"` + Name string + ProviderId string + Provider Provider `gorm:"foreignKey:ProviderId;references:Id"` Roles []Role `gorm:"many2many:groups_roles"` Users []User `gorm:"many2many:groups_users"` @@ -150,7 +150,7 @@ func (u *User) AfterCreate(tx *gorm.DB) error { // TODO (jmorganca): use foreign constraints instead? func (u *User) BeforeDelete(tx *gorm.DB) error { - if err := tx.Model(u).Association("Sources").Clear(); err != nil { + if err := tx.Model(u).Association("Providers").Clear(); err != nil { return fmt.Errorf("user associations before delete: %w", err) } @@ -258,22 +258,22 @@ func cleanUnassociatedRoles(tx *gorm.DB, roles []Role) error { return nil } -func (s *Source) BeforeCreate(tx *gorm.DB) (err error) { - if s.Id == "" { - s.Id = generate.MathRandString(IdLen) +func (p *Provider) BeforeCreate(tx *gorm.DB) (err error) { + if p.Id == "" { + p.Id = generate.MathRandString(IdLen) } return nil } -func (s *Source) BeforeDelete(tx *gorm.DB) error { +func (p *Provider) BeforeDelete(tx *gorm.DB) error { var users []User - if err := tx.Model(s).Association("Users").Find(&users); err != nil { + if err := tx.Model(p).Association("Users").Find(&users); err != nil { return err } for _, u := range users { - if err := s.DeleteUser(tx, u); err != nil { + if err := p.DeleteUser(tx, u); err != nil { return err } } @@ -281,17 +281,17 @@ func (s *Source) BeforeDelete(tx *gorm.DB) error { return nil } -// CreateUser will create a user and associate them with the source +// CreateUser will create a user and associate them with the provider // If the user already exists, they will not be created, instead an association // will be added instead -func (s *Source) CreateUser(db *gorm.DB, user *User, email string) error { +func (p *Provider) CreateUser(db *gorm.DB, user *User, email string) error { return db.Transaction(func(tx *gorm.DB) error { if err := tx.Where(&User{Email: email}).FirstOrCreate(&user).Error; err != nil { return err } - if tx.Model(&user).Where(&Source{Id: s.Id}).Association("Sources").Count() == 0 { - if err := tx.Model(&user).Where(&Source{Id: s.Id}).Association("Sources").Append(s); err != nil { + if tx.Model(&user).Where(&Provider{Id: p.Id}).Association("Providers").Count() == 0 { + if err := tx.Model(&user).Where(&Provider{Id: p.Id}).Association("Providers").Append(p); err != nil { return err } } @@ -300,16 +300,16 @@ func (s *Source) CreateUser(db *gorm.DB, user *User, email string) error { }) } -// Delete will delete a user's association with a source -// If this is their only source, then the user will be deleted entirely +// Delete will delete a user's association with a provider +// If this is their only provider, then the user will be deleted entirely // TODO (jmorganca): wrap this in a transaction or at least find out why // there seems to cause a bug when used in a nested transaction -func (s *Source) DeleteUser(db *gorm.DB, u User) error { - if err := db.Model(&u).Association("Sources").Delete(s); err != nil { +func (p *Provider) DeleteUser(db *gorm.DB, u User) error { + if err := db.Model(&u).Association("Providers").Delete(p); err != nil { return err } - if db.Model(&u).Association("Sources").Count() == 0 { + if db.Model(&u).Association("Providers").Count() == 0 { if err := db.Delete(&u).Error; err != nil { return err } @@ -318,37 +318,37 @@ func (s *Source) DeleteUser(db *gorm.DB, u User) error { return nil } -// Validate checks that an Okta source is valid -func (s *Source) Validate(r *Registry) error { - switch s.Kind { - case SourceKindOkta: - apiToken, err := r.GetSecret(s.APIToken) +// Validate checks that an Okta provider is valid +func (p *Provider) Validate(r *Registry) error { + switch p.Kind { + case ProviderKindOkta: + apiToken, err := r.GetSecret(p.APIToken) if err != nil { // this logs the expected secret object location, not the actual secret - return fmt.Errorf("could not retrieve okta API token from kubernetes secret %v: %w", s.APIToken, err) + return fmt.Errorf("could not retrieve okta API token from kubernetes secret %v: %w", p.APIToken, err) } - if _, err := r.GetSecret(s.ClientSecret); err != nil { - return fmt.Errorf("could not retrieve okta client secret %v: %w", s.ClientSecret, err) + if _, err := r.GetSecret(p.ClientSecret); err != nil { + return fmt.Errorf("could not retrieve okta client secret %v: %w", p.ClientSecret, err) } - return r.okta.ValidateOktaConnection(s.Domain, s.ClientID, apiToken) + return r.okta.ValidateOktaConnection(p.Domain, p.ClientID, apiToken) default: return nil } } -func (s *Source) SyncUsers(r *Registry) error { +func (p *Provider) SyncUsers(r *Registry) error { var emails []string - switch s.Kind { - case SourceKindOkta: - apiToken, err := r.GetSecret(s.APIToken) + switch p.Kind { + case ProviderKindOkta: + apiToken, err := r.GetSecret(p.APIToken) if err != nil { return fmt.Errorf("sync okta users api token: %w", err) } - emails, err = r.okta.Emails(s.Domain, s.ClientID, apiToken) + emails, err = r.okta.Emails(p.Domain, p.ClientID, apiToken) if err != nil { return fmt.Errorf("sync okta emails: %w", err) } @@ -357,21 +357,21 @@ func (s *Source) SyncUsers(r *Registry) error { } return r.db.Transaction(func(tx *gorm.DB) error { - // Create users in source + // Create users in provider for _, email := range emails { - if err := s.CreateUser(tx, &User{}, email); err != nil { + if err := p.CreateUser(tx, &User{}, email); err != nil { return fmt.Errorf("create user from okta: %w", err) } } - // Remove users from source that no longer exist in the identity provider + // Remove users from provider that no longer exist in the identity provider var toDelete []User if err := tx.Not("email IN ?", emails).Find(&toDelete).Error; err != nil { return fmt.Errorf("sync okta delete emails: %w", err) } for _, td := range toDelete { - if err := s.DeleteUser(tx, td); err != nil { + if err := p.DeleteUser(tx, td); err != nil { return fmt.Errorf("sync okta delete users: %w", err) } } @@ -380,17 +380,17 @@ func (s *Source) SyncUsers(r *Registry) error { }) } -func (s *Source) SyncGroups(r *Registry) error { +func (p *Provider) SyncGroups(r *Registry) error { var groupEmails map[string][]string - switch s.Kind { - case SourceKindOkta: - apiToken, err := r.GetSecret(s.APIToken) + switch p.Kind { + case ProviderKindOkta: + apiToken, err := r.GetSecret(p.APIToken) if err != nil { return fmt.Errorf("sync okta groups api secret: %w", err) } - groupEmails, err = r.okta.Groups(s.Domain, s.ClientID, apiToken) + groupEmails, err = r.okta.Groups(p.Domain, p.ClientID, apiToken) if err != nil { return fmt.Errorf("sync okta groups: %w", err) } @@ -402,7 +402,7 @@ func (s *Source) SyncGroups(r *Registry) error { var activeIDs []string for groupName, emails := range groupEmails { var group Group - if err := tx.FirstOrCreate(&group, Group{Name: groupName, SourceId: s.Id}).Error; err != nil { + if err := tx.FirstOrCreate(&group, Group{Name: groupName, ProviderId: p.Id}).Error; err != nil { logging.S.Debug("could not find or create okta group: " + groupName) return fmt.Errorf("sync create okta group: %w", err) } @@ -417,9 +417,9 @@ func (s *Source) SyncGroups(r *Registry) error { activeIDs = append(activeIDs, group.Id) } - // Delete source groups not in response + // Delete provider groups not in response var toDelete []Group - if err := tx.Where(&Group{SourceId: s.Id}).Not(activeIDs).Find(&toDelete).Error; err != nil { + if err := tx.Where(&Group{ProviderId: p.Id}).Not(activeIDs).Find(&toDelete).Error; err != nil { return fmt.Errorf("sync okta find inactive not in %d active: %w", len(activeIDs), err) } @@ -482,7 +482,7 @@ func (t *Token) BeforeCreate(tx *gorm.DB) (err error) { } // TODO (jmorganca): 24 hours may be too long or too short for some teams - // this should be customizable in settings or limited by the source's + // this should be customizable in settings or limited by the provider's // policy (e.g. Okta is often 1-3 hours) if t.Expires == 0 { t.Expires = time.Now().Add(SessionDuration).Unix() @@ -596,7 +596,7 @@ func NewDB(dbpath string) (*gorm.DB, error) { return nil, err } - if err := db.AutoMigrate(&Source{}); err != nil { + if err := db.AutoMigrate(&Provider{}); err != nil { return nil, err } diff --git a/internal/registry/data_test.go b/internal/registry/data_test.go index bb30b8f839..d15870f92b 100644 --- a/internal/registry/data_test.go +++ b/internal/registry/data_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/mock" ) -func TestSyncGroupsClearsOnlySource(t *testing.T) { - // mocks no groups being present at the source +func TestSyncGroupsClearsOnlyProvider(t *testing.T) { + // mocks no groups being present at the provider mockGroups := make(map[string][]string) testOkta := new(mocks.Okta) testOkta.On("Groups", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(mockGroups, nil) @@ -23,7 +23,7 @@ func TestSyncGroupsClearsOnlySource(t *testing.T) { }, } - if err := fakeOktaSource.SyncGroups(r); err != nil { + if err := fakeOktaProvider.SyncGroups(r); err != nil { t.Fatal(err) } @@ -49,12 +49,12 @@ func TestSyncGroupsFromOktaIgnoresUnknownUsers(t *testing.T) { }, } - if err := fakeOktaSource.SyncGroups(r); err != nil { + if err := fakeOktaProvider.SyncGroups(r); err != nil { t.Fatal(err) } var heroGroup Group - if err := db.Preload("Users").Where(&Group{Name: "heroes", SourceId: fakeOktaSource.Id}).First(&heroGroup).Error; err != nil { + if err := db.Preload("Users").Where(&Group{Name: "heroes", ProviderId: fakeOktaProvider.Id}).First(&heroGroup).Error; err != nil { t.Fatal(err) } @@ -76,12 +76,12 @@ func TestSyncGroupsFromOktaRecreatesGroups(t *testing.T) { }, } - if err := fakeOktaSource.SyncGroups(r); err != nil { + if err := fakeOktaProvider.SyncGroups(r); err != nil { t.Fatal(err) } var heroGroup Group - if err := db.Preload("Users").Where(&Group{Name: "heroes", SourceId: fakeOktaSource.Id}).First(&heroGroup).Error; err != nil { + if err := db.Preload("Users").Where(&Group{Name: "heroes", ProviderId: fakeOktaProvider.Id}).First(&heroGroup).Error; err != nil { t.Fatal(err) } @@ -90,11 +90,11 @@ func TestSyncGroupsFromOktaRecreatesGroups(t *testing.T) { mockGroups["villains"] = []string{"user@example.com"} - if err := fakeOktaSource.SyncGroups(r); err != nil { + if err := fakeOktaProvider.SyncGroups(r); err != nil { t.Fatal(err) } - if err := db.Preload("Users").Where(&Group{Name: "heroes", SourceId: fakeOktaSource.Id}).First(&heroGroup).Error; err != nil { + if err := db.Preload("Users").Where(&Group{Name: "heroes", ProviderId: fakeOktaProvider.Id}).First(&heroGroup).Error; err != nil { t.Fatal(err) } @@ -102,7 +102,7 @@ func TestSyncGroupsFromOktaRecreatesGroups(t *testing.T) { assert.Equal(t, heroGroup.Users[0].Email, "woz@example.com") var villainGroup Group - if err := db.Preload("Users").Where(&Group{Name: "villains", SourceId: fakeOktaSource.Id}).First(&villainGroup).Error; err != nil { + if err := db.Preload("Users").Where(&Group{Name: "villains", ProviderId: fakeOktaProvider.Id}).First(&villainGroup).Error; err != nil { t.Fatal(err) } diff --git a/internal/registry/registry.go b/internal/registry/registry.go index 7149eec0a5..6eb669556d 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -45,7 +45,7 @@ type Options struct { EnableTelemetry bool `mapstructure:"enable-telemetry"` EnableCrashReporting bool `mapstructure:"enable-crash-reporting"` - SourcesSyncInterval time.Duration `mapstructure:"sources-sync-interval"` + ProvidersSyncInterval time.Duration `mapstructure:"providers-sync-interval"` DestinationsSyncInterval time.Duration `mapstructure:"destinations-sync-interval"` internal.GlobalOptions @@ -63,33 +63,33 @@ type Registry struct { const ( rootAPIKeyName string = "root" engineAPIKeyName string = "engine" - DefaultSourcesSyncInterval time.Duration = time.Second * 60 + DefaultProvidersSyncInterval time.Duration = time.Second * 60 DefaultDestinationsSyncInterval time.Duration = time.Minute * 5 ) -// syncSources polls every known source for users and groups -func (r *Registry) syncSources() { - var sources []Source - if err := r.db.Find(&sources).Error; err != nil { - logging.S.Errorf("could not find sync sources: %w", err) +// syncProviders polls every known provider for users and groups +func (r *Registry) syncProviders() { + var providers []Provider + if err := r.db.Find(&providers).Error; err != nil { + logging.S.Errorf("could not find sync providers: %w", err) } - for _, s := range sources { - switch s.Kind { - case SourceKindOkta: - logging.L.Debug("synchronizing okta source") + for _, p := range providers { + switch p.Kind { + case ProviderKindOkta: + logging.L.Debug("synchronizing okta provider") - err := s.SyncUsers(r) + err := p.SyncUsers(r) if err != nil { logging.S.Errorf("sync okta users: %w", err) } - err = s.SyncGroups(r) + err = p.SyncGroups(r) if err != nil { logging.S.Errorf("sync okta groups: %w", err) } default: - logging.S.Errorf("skipped validating unknown source kind %s", s.Kind) + logging.S.Errorf("skipped validating unknown provider kind %s", p.Kind) } } } @@ -125,7 +125,7 @@ func Run(options Options) (err error) { r.okta = NewOkta() - r.validateSources() + r.validateProviders() r.scheduleSyncJobs() if err := r.configureTelemetry(); err != nil { @@ -175,21 +175,21 @@ func (r *Registry) loadConfigFromFile() (err error) { return nil } -// validateSources validates any existing or imported sources -func (r *Registry) validateSources() { - var sources []Source - if err := r.db.Find(&sources).Error; err != nil { - logging.S.Error("find sources to validate: %w", err) +// validateProviders validates any existing or imported providers +func (r *Registry) validateProviders() { + var providers []Provider + if err := r.db.Find(&providers).Error; err != nil { + logging.S.Error("find providers to validate: %w", err) } - for _, s := range sources { - switch s.Kind { - case SourceKindOkta: - if err := s.Validate(r); err != nil { + for _, p := range providers { + switch p.Kind { + case ProviderKindOkta: + if err := p.Validate(r); err != nil { logging.S.Errorf("could not validate okta: %w", err) } default: - logging.S.Errorf("skipped validating unknown source kind %s", s.Kind) + logging.S.Errorf("skipped validating unknown provider kind %s", p.Kind) } } } @@ -197,13 +197,13 @@ func (r *Registry) validateSources() { // schedule the user and group sync jobs func (r *Registry) scheduleSyncJobs() { // be careful with this sync job, there are Okta rate limits on these requests - syncSourcesTimer := timer.NewTimer() - defer syncSourcesTimer.Stop() - syncSourcesTimer.Start(r.options.SourcesSyncInterval, func() { - hub := newSentryHub("sync_sources_timer") + syncProvidersTimer := timer.NewTimer() + defer syncProvidersTimer.Stop() + syncProvidersTimer.Start(r.options.ProvidersSyncInterval, func() { + hub := newSentryHub("sync_providers_timer") defer recoverWithSentryHub(hub) - r.syncSources() + r.syncProviders() }) // schedule destination sync job diff --git a/internal/registry/telemetry.go b/internal/registry/telemetry.go index cdd03f66ef..e0a4c406e7 100644 --- a/internal/registry/telemetry.go +++ b/internal/registry/telemetry.go @@ -59,7 +59,7 @@ func (t *Telemetry) Close() { } func (t *Telemetry) EnqueueHeartbeat() error { - var users, groups, sources, destinations, roles int64 + var users, groups, providers, destinations, roles int64 if err := t.db.Model(&User{}).Count(&users).Error; err != nil { return err } @@ -68,7 +68,7 @@ func (t *Telemetry) EnqueueHeartbeat() error { return err } - if err := t.db.Model(&Source{}).Count(&sources).Error; err != nil { + if err := t.db.Model(&Provider{}).Count(&providers).Error; err != nil { return err } @@ -86,7 +86,7 @@ func (t *Telemetry) EnqueueHeartbeat() error { Properties: analytics.NewProperties(). Set("users", users). Set("groups", groups). - Set("sources", sources). + Set("providers", providers). Set("destinations", destinations). Set("roles", roles), }) diff --git a/internal/registry/ui/api/apis/SourcesApi.ts b/internal/registry/ui/api/apis/ProvidersApi.ts similarity index 58% rename from internal/registry/ui/api/apis/SourcesApi.ts rename to internal/registry/ui/api/apis/ProvidersApi.ts index 56a18e4d60..96a539b4ee 100644 --- a/internal/registry/ui/api/apis/SourcesApi.ts +++ b/internal/registry/ui/api/apis/ProvidersApi.ts @@ -15,30 +15,30 @@ import * as runtime from '../runtime'; import { - Source, - SourceFromJSON, - SourceToJSON, + Provider, + ProviderFromJSON, + ProviderToJSON, } from '../models'; -export interface GetSourceRequest { +export interface GetProviderRequest { id: string; } -export interface ListSourcesRequest { +export interface ListProvidersRequest { kind?: string; } /** * */ -export class SourcesApi extends runtime.BaseAPI { +export class ProvidersApi extends runtime.BaseAPI { /** - * Get source by ID + * Get provider by ID */ - async getSourceRaw(requestParameters: GetSourceRequest, initOverrides?: RequestInit): Promise> { + async getProviderRaw(requestParameters: GetProviderRequest, initOverrides?: RequestInit): Promise> { if (requestParameters.id === null || requestParameters.id === undefined) { - throw new runtime.RequiredError('id','Required parameter requestParameters.id was null or undefined when calling getSource.'); + throw new runtime.RequiredError('id','Required parameter requestParameters.id was null or undefined when calling getProvider.'); } const queryParameters: any = {}; @@ -46,27 +46,27 @@ export class SourcesApi extends runtime.BaseAPI { const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/sources/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters.id))), + path: `/providers/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters.id))), method: 'GET', headers: headerParameters, query: queryParameters, }, initOverrides); - return new runtime.JSONApiResponse(response, (jsonValue) => SourceFromJSON(jsonValue)); + return new runtime.JSONApiResponse(response, (jsonValue) => ProviderFromJSON(jsonValue)); } /** - * Get source by ID + * Get provider by ID */ - async getSource(requestParameters: GetSourceRequest, initOverrides?: RequestInit): Promise { - const response = await this.getSourceRaw(requestParameters, initOverrides); + async getProvider(requestParameters: GetProviderRequest, initOverrides?: RequestInit): Promise { + const response = await this.getProviderRaw(requestParameters, initOverrides); return await response.value(); } /** - * List sources + * List providers */ - async listSourcesRaw(requestParameters: ListSourcesRequest, initOverrides?: RequestInit): Promise>> { + async listProvidersRaw(requestParameters: ListProvidersRequest, initOverrides?: RequestInit): Promise>> { const queryParameters: any = {}; if (requestParameters.kind !== undefined) { @@ -76,20 +76,20 @@ export class SourcesApi extends runtime.BaseAPI { const headerParameters: runtime.HTTPHeaders = {}; const response = await this.request({ - path: `/sources`, + path: `/providers`, method: 'GET', headers: headerParameters, query: queryParameters, }, initOverrides); - return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(SourceFromJSON)); + return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(ProviderFromJSON)); } /** - * List sources + * List providers */ - async listSources(requestParameters: ListSourcesRequest, initOverrides?: RequestInit): Promise> { - const response = await this.listSourcesRaw(requestParameters, initOverrides); + async listProviders(requestParameters: ListProvidersRequest, initOverrides?: RequestInit): Promise> { + const response = await this.listProvidersRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/internal/registry/ui/api/apis/index.ts b/internal/registry/ui/api/apis/index.ts index aa9f6258ea..c92fc82d3e 100644 --- a/internal/registry/ui/api/apis/index.ts +++ b/internal/registry/ui/api/apis/index.ts @@ -4,8 +4,8 @@ export * from './ApiKeysApi'; export * from './AuthApi'; export * from './DestinationsApi'; export * from './GroupsApi'; +export * from './ProvidersApi'; export * from './RolesApi'; -export * from './SourcesApi'; export * from './TokensApi'; export * from './UsersApi'; export * from './VersionApi'; diff --git a/internal/registry/ui/api/models/Group.ts b/internal/registry/ui/api/models/Group.ts index 43efb1269f..fe5f8bf4a1 100644 --- a/internal/registry/ui/api/models/Group.ts +++ b/internal/registry/ui/api/models/Group.ts @@ -59,7 +59,7 @@ export interface Group { * @type {string} * @memberof Group */ - sourceID: string; + providerID: string; /** * * @type {Array} @@ -88,7 +88,7 @@ export function GroupFromJSONTyped(json: any, ignoreDiscriminator: boolean): Gro 'name': json['name'], 'created': json['created'], 'updated': json['updated'], - 'sourceID': json['sourceID'], + 'providerID': json['providerID'], 'users': ((json['users'] as Array).map(UserFromJSON)), 'roles': ((json['roles'] as Array).map(RoleFromJSON)), }; @@ -107,7 +107,7 @@ export function GroupToJSON(value?: Group | null): any { 'name': value.name, 'created': value.created, 'updated': value.updated, - 'sourceID': value.sourceID, + 'providerID': value.providerID, 'users': ((value.users as Array).map(UserToJSON)), 'roles': ((value.roles as Array).map(RoleToJSON)), }; diff --git a/internal/registry/ui/api/models/Source.ts b/internal/registry/ui/api/models/Provider.ts similarity index 66% rename from internal/registry/ui/api/models/Source.ts rename to internal/registry/ui/api/models/Provider.ts index 5d5e44d1a9..0620124297 100644 --- a/internal/registry/ui/api/models/Source.ts +++ b/internal/registry/ui/api/models/Provider.ts @@ -14,73 +14,73 @@ import { exists, mapValues } from '../runtime'; import { - SourceOkta, - SourceOktaFromJSON, - SourceOktaFromJSONTyped, - SourceOktaToJSON, + ProviderOkta, + ProviderOktaFromJSON, + ProviderOktaFromJSONTyped, + ProviderOktaToJSON, } from './'; /** * * @export - * @interface Source + * @interface Provider */ -export interface Source { +export interface Provider { /** * * @type {string} - * @memberof Source + * @memberof Provider */ id: string; /** * * @type {number} - * @memberof Source + * @memberof Provider */ created: number; /** * * @type {number} - * @memberof Source + * @memberof Provider */ updated: number; /** * * @type {string} - * @memberof Source + * @memberof Provider */ domain: string; /** * * @type {string} - * @memberof Source + * @memberof Provider */ clientID: string; /** * * @type {string} - * @memberof Source + * @memberof Provider */ clientSecret: string; /** * * @type {string} - * @memberof Source + * @memberof Provider */ kind: string; /** * - * @type {SourceOkta} - * @memberof Source + * @type {ProviderOkta} + * @memberof Provider */ - okta?: SourceOkta; + okta?: ProviderOkta; } -export function SourceFromJSON(json: any): Source { - return SourceFromJSONTyped(json, false); +export function ProviderFromJSON(json: any): Provider { + return ProviderFromJSONTyped(json, false); } -export function SourceFromJSONTyped(json: any, ignoreDiscriminator: boolean): Source { +export function ProviderFromJSONTyped(json: any, ignoreDiscriminator: boolean): Provider { if ((json === undefined) || (json === null)) { return json; } @@ -93,11 +93,11 @@ export function SourceFromJSONTyped(json: any, ignoreDiscriminator: boolean): So 'clientID': json['clientID'], 'clientSecret': json['clientSecret'], 'kind': json['kind'], - 'okta': !exists(json, 'okta') ? undefined : SourceOktaFromJSON(json['okta']), + 'okta': !exists(json, 'okta') ? undefined : ProviderOktaFromJSON(json['okta']), }; } -export function SourceToJSON(value?: Source | null): any { +export function ProviderToJSON(value?: Provider | null): any { if (value === undefined) { return undefined; } @@ -113,7 +113,7 @@ export function SourceToJSON(value?: Source | null): any { 'clientID': value.clientID, 'clientSecret': value.clientSecret, 'kind': value.kind, - 'okta': SourceOktaToJSON(value.okta), + 'okta': ProviderOktaToJSON(value.okta), }; } diff --git a/internal/registry/ui/api/models/SourceOkta.ts b/internal/registry/ui/api/models/ProviderOkta.ts similarity index 67% rename from internal/registry/ui/api/models/SourceOkta.ts rename to internal/registry/ui/api/models/ProviderOkta.ts index b3afbf9771..3ba9171f0b 100644 --- a/internal/registry/ui/api/models/SourceOkta.ts +++ b/internal/registry/ui/api/models/ProviderOkta.ts @@ -16,22 +16,22 @@ import { exists, mapValues } from '../runtime'; /** * * @export - * @interface SourceOkta + * @interface ProviderOkta */ -export interface SourceOkta { +export interface ProviderOkta { /** * * @type {string} - * @memberof SourceOkta + * @memberof ProviderOkta */ apiToken: string; } -export function SourceOktaFromJSON(json: any): SourceOkta { - return SourceOktaFromJSONTyped(json, false); +export function ProviderOktaFromJSON(json: any): ProviderOkta { + return ProviderOktaFromJSONTyped(json, false); } -export function SourceOktaFromJSONTyped(json: any, ignoreDiscriminator: boolean): SourceOkta { +export function ProviderOktaFromJSONTyped(json: any, ignoreDiscriminator: boolean): ProviderOkta { if ((json === undefined) || (json === null)) { return json; } @@ -41,7 +41,7 @@ export function SourceOktaFromJSONTyped(json: any, ignoreDiscriminator: boolean) }; } -export function SourceOktaToJSON(value?: SourceOkta | null): any { +export function ProviderOktaToJSON(value?: ProviderOkta | null): any { if (value === undefined) { return undefined; } diff --git a/internal/registry/ui/api/models/index.ts b/internal/registry/ui/api/models/index.ts index 8aa84ee8f7..08e84a6b9c 100644 --- a/internal/registry/ui/api/models/index.ts +++ b/internal/registry/ui/api/models/index.ts @@ -12,10 +12,10 @@ export * from './LoginRequest'; export * from './LoginRequestOkta'; export * from './LoginResponse'; export * from './ModelError'; +export * from './Provider'; +export * from './ProviderOkta'; export * from './Role'; export * from './RoleKind'; -export * from './Source'; -export * from './SourceOkta'; export * from './Token'; export * from './TokenRequest'; export * from './User'; diff --git a/openapi.yaml b/openapi.yaml index 8a242d262d..6922e3e933 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -15,8 +15,8 @@ tags: description: Manage groups - name: roles description: Manage roles - - name: sources - description: Manage identity sources + - name: providers + description: Manage identity providers - name: destinations description: Manage infrastructure destinations - name: tokens @@ -152,53 +152,53 @@ paths: application/json: schema: $ref: 'openapi/utils.yaml#/Error' - /sources: + /providers: get: - summary: List sources + summary: List providers tags: - - sources - operationId: listSources + - providers + operationId: listProviders parameters: - in: query name: kind schema: type: string - description: Filter sources by kind + description: Filter providers by kind responses: '200': - description: List sources response + description: List providers response content: application/json: schema: type: array items: - $ref: 'openapi/source.yaml#/Source' + $ref: 'openapi/provider.yaml#/Provider' default: description: Error response content: application/json: schema: $ref: 'openapi/utils.yaml#/Error' - /sources/{id}: + /providers/{id}: get: - summary: Get source by ID + summary: Get provider by ID tags: - - sources - operationId: getSource + - providers + operationId: getProvider parameters: - in: path name: id required: true schema: type: string - description: Source ID + description: Provider ID responses: '200': - description: Get source response + description: Get provider response content: application/json: schema: - $ref: 'openapi/source.yaml#/Source' + $ref: 'openapi/provider.yaml#/Provider' default: description: Error response content: diff --git a/openapi/group.yaml b/openapi/group.yaml index 956464df3e..a6e382fca3 100644 --- a/openapi/group.yaml +++ b/openapi/group.yaml @@ -7,7 +7,7 @@ Group: - updated - users - roles - - sourceID + - providerID properties: id: type: string @@ -19,7 +19,7 @@ Group: updated: type: integer format: int64 - sourceID: + providerID: type: string users: type: array diff --git a/openapi/source.yaml b/openapi/provider.yaml similarity index 90% rename from openapi/source.yaml rename to openapi/provider.yaml index 36b7df6545..4aefa7ecfd 100644 --- a/openapi/source.yaml +++ b/openapi/provider.yaml @@ -1,4 +1,4 @@ -Source: +Provider: type: object required: - id @@ -29,9 +29,9 @@ Source: type: string x-go-custom-tag: validate:"required" okta: - $ref: 'source.yaml#/SourceOkta' + $ref: 'provider.yaml#/ProviderOkta' -SourceOkta: +ProviderOkta: type: object required: - apiToken