diff --git a/disco/host.go b/disco/host.go index 2d0fc9f..d0ec8ee 100644 --- a/disco/host.go +++ b/disco/host.go @@ -255,6 +255,17 @@ func (h *Host) ServiceOAuthClient(id string) (*OAuthClient, error) { ret.MinPort = 1024 ret.MaxPort = 65535 } + if scopesRaw, ok := raw["scopes"].([]interface{}); ok { + var scopes []string + for _, scopeI := range scopesRaw { + scope, ok := scopeI.(string) + if !ok { + return nil, fmt.Errorf("Invalid \"scopes\" for service %s: all scopes must be strings", id) + } + scopes = append(scopes, scope) + } + ret.Scopes = scopes + } return ret, nil } diff --git a/disco/host_test.go b/disco/host_test.go index b87fa70..ad18f1b 100644 --- a/disco/host_test.go +++ b/disco/host_test.go @@ -148,6 +148,24 @@ func TestHostServiceOAuthClient(t *testing.T) { "authz": "/foo", "token": "***not A URL at all!:/<@@@@>***", }, + "scopesincluded.v1": map[string]interface{}{ + "client": "scopesincluded", + "authz": "/auth", + "token": "/token", + "scopes": []interface{}{"app1.full_access", "app2.read_only"}, + }, + "scopesempty.v1": map[string]interface{}{ + "client": "scopesempty", + "authz": "/auth", + "token": "/token", + "scopes": []interface{}{}, + }, + "scopesbad.v1": map[string]interface{}{ + "client": "scopesbad", + "authz": "/auth", + "token": "/token", + "scopes": []interface{}{"app1.full_access", 42}, + }, }, } @@ -290,6 +308,36 @@ func TestHostServiceOAuthClient(t *testing.T) { nil, "Failed to parse token URL: parse \"***not A URL at all!:/<@@@@>***\": first path segment in URL cannot contain colon", }, + { + "scopesincluded.v1", + &OAuthClient{ + ID: "scopesincluded", + AuthorizationURL: mustURL(t, "https://example.com/auth"), + TokenURL: mustURL(t, "https://example.com/token"), + MinPort: 1024, + MaxPort: 65535, + SupportedGrantTypes: NewOAuthGrantTypeSet("authz_code"), + Scopes: []string{"app1.full_access", "app2.read_only"}, + }, + "", + }, + { + "scopesempty.v1", + &OAuthClient{ + ID: "scopesempty", + AuthorizationURL: mustURL(t, "https://example.com/auth"), + TokenURL: mustURL(t, "https://example.com/token"), + MinPort: 1024, + MaxPort: 65535, + SupportedGrantTypes: NewOAuthGrantTypeSet("authz_code"), + }, + "", + }, + { + "scopesbad.v1", + nil, + `Invalid "scopes" for service scopesbad.v1: all scopes must be strings`, + }, } for _, test := range tests { diff --git a/disco/oauth_client.go b/disco/oauth_client.go index 9308bbf..9df16eb 100644 --- a/disco/oauth_client.go +++ b/disco/oauth_client.go @@ -46,6 +46,11 @@ type OAuthClient struct { // by the server, even if a particular keyword is not supported by the // current version of Terraform. SupportedGrantTypes OAuthGrantTypeSet + + // Oauth2 does not require scopes for the authorization endpoint, however + // OIDC does. Optional list of scopes to include in auth code and token + // requests. + Scopes []string } // Endpoint returns an oauth2.Endpoint value ready to be used with the oauth2