Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DXCDT-256: Add support for Okta connection #130

Merged
merged 1 commit into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion management/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
const (
// ConnectionStrategyAuth0 constant.
ConnectionStrategyAuth0 = "auth0"
// ConnectionStrategyOkta constant.
ConnectionStrategyOkta = "okta"
// ConnectionStrategyGoogleOAuth2 constant.
ConnectionStrategyGoogleOAuth2 = "google-oauth2"
// ConnectionStrategyFacebook constant.
Expand Down Expand Up @@ -111,7 +113,7 @@ type Connection struct {
// "salesforce", "samlp", "sharepoint", "shopify", "sms", "soundcloud",
// "thecity-sandbox", "thecity", "thirtysevensignals", "twitter", "untappd",
// "vkontakte", "waad", "weibo", "windowslive", "wordpress", "yahoo",
// "yammer" or "yandex".
// "yammer", "okta" or "yandex".
Strategy *string `json:"strategy,omitempty"`

// True if the connection is domain level
Expand Down Expand Up @@ -181,6 +183,8 @@ func (c *Connection) UnmarshalJSON(b []byte) error {
switch *c.Strategy {
case ConnectionStrategyAuth0:
v = &ConnectionOptions{}
case ConnectionStrategyOkta:
v = &ConnectionOptionsOkta{}
case ConnectionStrategyGoogleOAuth2:
v = &ConnectionOptionsGoogleOAuth2{}
case ConnectionStrategyFacebook:
Expand Down Expand Up @@ -298,6 +302,48 @@ type ConnectionOptions struct {
UpstreamParams map[string]interface{} `json:"upstream_params,omitempty"`
}

// ConnectionOptionsOkta is used to configure an Okta Workforce Connection.
type ConnectionOptionsOkta struct {
ClientID *string `json:"client_id,omitempty"`
ClientSecret *string `json:"client_secret,omitempty"`
Domain *string `json:"domain,omitempty"`
DomainAliases *[]string `json:"domain_aliases,omitempty"`
AuthorizationEndpoint *string `json:"authorization_endpoint"`
Issuer *string `json:"issuer"`
JWKSURI *string `json:"jwks_uri"`
UserInfoEndpoint *string `json:"userinfo_endpoint"`
TokenEndpoint *string `json:"token_endpoint"`
Scope *string `json:"scope,omitempty"`
SetUserAttributes *string `json:"set_user_root_attributes,omitempty"`
NonPersistentAttrs *[]string `json:"non_persistent_attrs,omitempty"`
UpstreamParams map[string]interface{} `json:"upstream_params,omitempty"`
}

// Scopes returns the scopes for ConnectionOptionsOkta.
func (c *ConnectionOptionsOkta) Scopes() []string {
return strings.Fields(c.GetScope())
}

// SetScopes sets the scopes for ConnectionOptionsOkta.
func (c *ConnectionOptionsOkta) SetScopes(enable bool, scopes ...string) {
scopeMap := make(map[string]bool)
for _, scope := range c.Scopes() {
scopeMap[scope] = true
}
for _, scope := range scopes {
scopeMap[scope] = enable
}
scopeSlice := make([]string, 0, len(scopeMap))
for scope, enabled := range scopeMap {
if enabled {
scopeSlice = append(scopeSlice, scope)
}
}
sort.Strings(scopeSlice)
scope := strings.Join(scopeSlice, " ")
c.Scope = &scope
}

// ConnectionOptionsGoogleOAuth2 is used to configure a GoogleOAuth2 Connection.
type ConnectionOptionsGoogleOAuth2 struct {
ClientID *string `json:"client_id,omitempty"`
Expand Down
39 changes: 36 additions & 3 deletions management/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,27 @@ ZsUkLw2I7zI/dNlWdB8Xp7v+3w9sX5N3J/WuJ1KOO5m26kRlHQo7EzT3974g
},
},
},
{
name: "Okta Connection",
connection: Connection{
Name: auth0.Stringf("Test-Okta-Connection-%d", time.Now().Unix()),
Strategy: auth0.String("okta"),
},
options: &ConnectionOptionsOkta{
ClientID: auth0.String("4ef8d976-71bd-4473-a7ce-087d3f0fafd8"),
ClientSecret: auth0.String("mySecret"),
Scope: auth0.String("openid"),
Domain: auth0.String("domain.okta.com"),
Issuer: auth0.String("https://example.com"),
AuthorizationEndpoint: auth0.String("https://example.com"),
JWKSURI: auth0.String("https://example.com/jwks"),
UpstreamParams: map[string]interface{}{
"screen_name": map[string]interface{}{
"alias": "login_hint",
},
},
},
},
}

type connectionTestCase struct {
Expand Down Expand Up @@ -405,8 +426,10 @@ func TestConnectionManager_ReadByName(t *testing.T) {
func TestConnectionManager_Update(t *testing.T) {
for _, testCase := range connectionTestCases {
t.Run("It can successfully update a "+testCase.name, func(t *testing.T) {
if testCase.connection.GetStrategy() == "oidc" || testCase.connection.GetStrategy() == "samlp" {
t.Skip("Skipping because we can't create an oidc or samlp connection with no options")
if testCase.connection.GetStrategy() == "oidc" ||
testCase.connection.GetStrategy() == "samlp" ||
testCase.connection.GetStrategy() == "okta" {
t.Skip("Skipping because we can't create an oidc, okta or samlp connection with no options")
}

setupHTTPRecordings(t)
Expand Down Expand Up @@ -477,7 +500,7 @@ func TestConnectionOptionsScopes(t *testing.T) {
assert.Equal(t, []string{"bar"}, options.Scopes())
})

t.Run("It can successfully set the scopes on the options of a OAuth2 connection", func(t *testing.T) {
t.Run("It can successfully set the scopes on the options of an OAuth2 connection", func(t *testing.T) {
options := &ConnectionOptionsOAuth2{}

options.SetScopes(true, "foo", "bar", "baz")
Expand All @@ -486,6 +509,16 @@ func TestConnectionOptionsScopes(t *testing.T) {
options.SetScopes(false, "foo", "baz")
assert.Equal(t, []string{"bar"}, options.Scopes())
})

t.Run("It can successfully set the scopes on the options of an Okta connection", func(t *testing.T) {
options := &ConnectionOptionsOkta{}

options.SetScopes(true, "foo", "bar", "baz")
assert.Equal(t, []string{"bar", "baz", "foo"}, options.Scopes())

options.SetScopes(false, "foo", "baz")
assert.Equal(t, []string{"bar"}, options.Scopes())
})
}

func cleanupConnection(t *testing.T, connectionID string) {
Expand Down
101 changes: 101 additions & 0 deletions management/management.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions management/management.gen_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading