Add SSWS API-key Authorization scheme
Okta API tokens authenticate as "Authorization: SSWS <token>", a scheme none of the existing API-key modes (Bearer, custom header, Basic) can express. Add Registration.APIKeyAuthScheme, plumb it onto APIKeyConnection.Scheme, and send it via a new schemeAuthTransport. The three API-key presentations (BasicAuth, Header, Scheme) are mutually exclusive; Register rejects setting more than one so a misconfiguration fails at process start rather than silently. Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
@@ -71,11 +71,26 @@ func (r *Registry) Register(reg *Registration) error {
|
||||
return fmt.Errorf("cannot register connector provider %q: missing DisplayName", reg.Provider)
|
||||
}
|
||||
|
||||
// APIKeyBasicAuth and APIKeyHeader select different presentations of
|
||||
// the same key; setting both is a programmer error with a silent
|
||||
// winner (Client checks BasicAuth first). Reject it at startup.
|
||||
if reg.APIKeyBasicAuth && reg.APIKeyHeader != "" {
|
||||
return fmt.Errorf("cannot register connector provider %q: APIKeyBasicAuth and APIKeyHeader are mutually exclusive", reg.Provider)
|
||||
// APIKeyBasicAuth, APIKeyHeader, and APIKeyAuthScheme select different
|
||||
// presentations of the same key; setting more than one is a programmer
|
||||
// error with a silent winner (Client checks BasicAuth, then Header,
|
||||
// then Scheme). Reject it at startup.
|
||||
apiKeyModes := 0
|
||||
|
||||
if reg.APIKeyBasicAuth {
|
||||
apiKeyModes++
|
||||
}
|
||||
|
||||
if reg.APIKeyHeader != "" {
|
||||
apiKeyModes++
|
||||
}
|
||||
|
||||
if reg.APIKeyAuthScheme != "" {
|
||||
apiKeyModes++
|
||||
}
|
||||
|
||||
if apiKeyModes > 1 {
|
||||
return fmt.Errorf("cannot register connector provider %q: APIKeyBasicAuth, APIKeyHeader, and APIKeyAuthScheme are mutually exclusive", reg.Provider)
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
@@ -170,6 +185,19 @@ func (r *Registry) APIKeyUsesBasicAuth(p coredata.ConnectorProvider) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// APIKeyAuthScheme returns the non-Bearer Authorization scheme an API-key
|
||||
// connection for the given provider must use to present its key (e.g.
|
||||
// "SSWS" for Okta). Empty means the default `Authorization: Bearer`
|
||||
// scheme. Returns empty for unknown providers and for providers that do
|
||||
// not customise the scheme.
|
||||
func (r *Registry) APIKeyAuthScheme(p coredata.ConnectorProvider) string {
|
||||
if reg, ok := r.Get(p); ok {
|
||||
return reg.APIKeyAuthScheme
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// ProviderOAuth2Scopes returns the OAuth2 scopes the access review
|
||||
// driver for the given provider needs to list user accounts. Returns
|
||||
// nil for providers that do not need any scopes (Notion, Intercom)
|
||||
|
||||
@@ -95,6 +95,20 @@ func TestRegistry_Register(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "mutually exclusive")
|
||||
})
|
||||
|
||||
t.Run("APIKeyAuthScheme and APIKeyHeader mutually exclusive", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := provider.NewRegistry()
|
||||
err := r.Register(&provider.Registration{
|
||||
Provider: coredata.ConnectorProviderSlack,
|
||||
DisplayName: "Slack",
|
||||
APIKeyAuthScheme: "SSWS",
|
||||
APIKeyHeader: "x-api-key",
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "mutually exclusive")
|
||||
})
|
||||
|
||||
t.Run("duplicate registration", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -87,6 +87,15 @@ type Registration struct {
|
||||
// APIKeyHeader. Consumed when the create-connector resolver builds
|
||||
// the APIKeyConnection.
|
||||
APIKeyBasicAuth bool
|
||||
// APIKeyAuthScheme selects a non-Bearer Authorization scheme for an
|
||||
// API-key connection: the key is sent as `Authorization: <scheme>
|
||||
// <key>` instead of `Authorization: Bearer <key>`. Required by
|
||||
// providers such as Okta whose API tokens use the `SSWS` scheme and
|
||||
// reject Bearer. Empty (the default) keeps the standard Bearer
|
||||
// scheme. Mutually exclusive with APIKeyHeader and APIKeyBasicAuth.
|
||||
// Consumed when the create-connector resolver builds the
|
||||
// APIKeyConnection.
|
||||
APIKeyAuthScheme string
|
||||
|
||||
// Factory closures — wired by Stages 2 and 3.
|
||||
NewDriver func(context.Context, *http.Client, *coredata.Connector, *log.Logger) (drivers.Driver, error)
|
||||
|
||||
Reference in New Issue
Block a user