-
Notifications
You must be signed in to change notification settings - Fork 55
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-296: Supporting additional scopes when authenticating as user #561
Changes from 20 commits
253f880
4cea50f
2cb6f19
06723ec
73ea1c9
d55fd0d
1aef346
b96c834
c3541b0
607a197
e8df004
7d58fa9
cb0e08f
a2f5860
9be2ed0
d5caf06
976f9a2
e23b9b2
d823184
03bea62
cc62501
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,50 +25,23 @@ const ( | |
|
||
var requiredScopes = []string{ | ||
"openid", | ||
"offline_access", // This is used to retrieve a refresh token. | ||
"create:clients", "read:clients", "update:clients", "delete:clients", | ||
"read:client_keys", | ||
"create:client_grants", "read:client_grants", "update:client_grants", "delete:client_grants", | ||
"create:resource_servers", "read:resource_servers", "update:resource_servers", "delete:resource_servers", | ||
"create:connections", "read:connections", "update:connections", "delete:connections", | ||
"create:users", "read:users", "update:users", "delete:users", | ||
"create:roles", "read:roles", "update:roles", "delete:roles", | ||
"create:actions", "read:actions", "update:actions", "delete:actions", | ||
"read:triggers", "update:triggers", | ||
"create:rules", "read:rules", "update:rules", "delete:rules", | ||
"read:rules_configs", "update:rules_configs", "delete:rules_configs", | ||
"create:hooks", "read:hooks", "update:hooks", "delete:hooks", | ||
"read:attack_protection", "update:attack_protection", | ||
"create:organizations", "read:organizations", "update:organizations", "delete:organizations", | ||
"create:organization_members", "read:organization_members", "delete:organization_members", | ||
"create:organization_connections", "read:organization_connections", "update:organization_connections", "delete:organization_connections", | ||
"create:organization_member_roles", "read:organization_member_roles", "delete:organization_member_roles", | ||
"create:organization_invitations", "read:organization_invitations", "delete:organization_invitations", | ||
"read:prompts", "update:prompts", | ||
"read:branding", "update:branding", "delete:branding", | ||
"create:custom_domains", "read:custom_domains", "update:custom_domains", "delete:custom_domains", | ||
"create:email_provider", "read:email_provider", "update:email_provider", "delete:email_provider", | ||
"create:email_templates", "read:email_templates", "update:email_templates", | ||
"read:tenant_settings", "update:tenant_settings", | ||
"offline_access", // for retrieving refresh token | ||
"create:clients", "delete:clients", "read:clients", "update:clients", | ||
"create:resource_servers", "delete:resource_servers", "read:resource_servers", "update:resource_servers", | ||
"create:roles", "delete:roles", "read:roles", "update:roles", | ||
"create:rules", "delete:rules", "read:rules", "update:rules", | ||
"create:users", "delete:users", "read:users", "update:users", | ||
"read:branding", "update:branding", | ||
"read:email_templates", "update:email_templates", | ||
"read:connections", "update:connections", | ||
"read:client_keys", "read:logs", "read:tenant_settings", | ||
"read:custom_domains", "create:custom_domains", "update:custom_domains", "delete:custom_domains", | ||
"read:anomaly_blocks", "delete:anomaly_blocks", | ||
"create:log_streams", "read:log_streams", "update:log_streams", "delete:log_streams", | ||
"read:stats", | ||
"read:insights", | ||
"read:logs", | ||
"create:shields", "read:shields", "update:shields", "delete:shields", | ||
"create:users_app_metadata", "read:users_app_metadata", "update:users_app_metadata", "delete:users_app_metadata", | ||
"create:user_custom_blocks", "read:user_custom_blocks", "delete:user_custom_blocks", | ||
"create:user_tickets", | ||
"blacklist:tokens", | ||
"read:grants", "delete:grants", | ||
"read:mfa_policies", "update:mfa_policies", | ||
"read:guardian_factors", "update:guardian_factors", | ||
"read:guardian_enrollments", "delete:guardian_enrollments", | ||
"create:guardian_enrollment_tickets", | ||
"read:user_idp_tokens", | ||
"create:passwords_checking_job", "delete:passwords_checking_job", | ||
"read:limits", "update:limits", | ||
"read:entitlements", | ||
"create:log_streams", "delete:log_streams", "read:log_streams", "update:log_streams", | ||
"create:actions", "delete:actions", "read:actions", "update:actions", | ||
"create:organizations", "delete:organizations", "read:organizations", "update:organizations", "read:organization_members", "read:organization_member_roles", | ||
"read:prompts", "update:prompts", | ||
"read:attack_protection", "update:attack_protection", | ||
} | ||
|
||
// Authenticator is used to facilitate the login process. | ||
|
@@ -123,7 +96,7 @@ func (s *State) IntervalDuration() time.Duration { | |
return time.Duration(s.Interval+waitThresholdInSeconds) * time.Second | ||
} | ||
|
||
// New returns a new instance of Authenticator using Auth0 Public Cloud default values | ||
// New returns a new instance of Authenticator using Auth0 Public Cloud default values. | ||
func New() *Authenticator { | ||
return &Authenticator{ | ||
Audience: "https://*.auth0.com/api/v2/", | ||
|
@@ -133,18 +106,6 @@ func New() *Authenticator { | |
} | ||
} | ||
|
||
// Start kicks-off the device authentication flow by requesting | ||
// a device code from Auth0. The returned state contains the | ||
// URI for the next step of the flow. | ||
func (a *Authenticator) Start(ctx context.Context) (State, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bit of a refactor here. Removing the |
||
state, err := a.getDeviceCode(ctx) | ||
if err != nil { | ||
return State{}, fmt.Errorf("failed to get the device code: %w", err) | ||
} | ||
|
||
return state, nil | ||
} | ||
|
||
// Wait waits until the user is logged in on the browser. | ||
func (a *Authenticator) Wait(ctx context.Context, state State) (Result, error) { | ||
t := time.NewTicker(state.IntervalDuration()) | ||
|
@@ -205,10 +166,13 @@ func (a *Authenticator) Wait(ctx context.Context, state State) (Result, error) { | |
} | ||
} | ||
|
||
func (a *Authenticator) getDeviceCode(ctx context.Context) (State, error) { | ||
// GetDeviceCode kicks-off the device authentication flow by requesting | ||
// a device code from Auth0. The returned state contains the | ||
// URI for the next step of the flow. | ||
func (a *Authenticator) GetDeviceCode(ctx context.Context, additionalScopes []string) (State, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only functional change here is the addition of the |
||
data := url.Values{ | ||
"client_id": []string{a.ClientID}, | ||
"scope": []string{strings.Join(requiredScopes, " ")}, | ||
"scope": []string{strings.Join(append(requiredScopes, additionalScopes...), " ")}, | ||
"audience": []string{a.Audience}, | ||
} | ||
|
||
|
@@ -219,7 +183,7 @@ func (a *Authenticator) getDeviceCode(ctx context.Context) (State, error) { | |
strings.NewReader(data.Encode()), | ||
) | ||
if err != nil { | ||
return State{}, fmt.Errorf("failed to create the request: %w", err) | ||
return State{}, fmt.Errorf("failed to create the request: %w, ", err) | ||
sergiught marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
|
@@ -230,7 +194,7 @@ func (a *Authenticator) getDeviceCode(ctx context.Context) (State, error) { | |
} | ||
defer response.Body.Close() | ||
|
||
if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusBadRequest { | ||
if response.StatusCode != http.StatusOK { | ||
bodyBytes, err := io.ReadAll(response.Body) | ||
if err != nil { | ||
return State{}, fmt.Errorf( | ||
|
@@ -243,8 +207,7 @@ func (a *Authenticator) getDeviceCode(ctx context.Context) (State, error) { | |
} | ||
|
||
var state State | ||
err = json.NewDecoder(response.Body).Decode(&state) | ||
if err != nil { | ||
if err = json.NewDecoder(response.Body).Decode(&state); err != nil { | ||
return State{}, fmt.Errorf("failed to decode the response: %w", err) | ||
} | ||
|
||
|
@@ -277,14 +240,14 @@ func parseTenant(accessToken string) (tenant, domain string, err error) { | |
return "", "", fmt.Errorf("audience not found for %s", audiencePath) | ||
} | ||
|
||
// ClientCredentials encapsulates all data to facilitate access token creation with client credentials (client ID and client secret) | ||
// ClientCredentials encapsulates all data to facilitate access token creation with client credentials (client ID and client secret). | ||
type ClientCredentials struct { | ||
ClientID string | ||
ClientSecret string | ||
Domain string | ||
} | ||
|
||
// GetAccessTokenFromClientCreds generates an access token from client credentials | ||
// GetAccessTokenFromClientCreds generates an access token from client credentials. | ||
func GetAccessTokenFromClientCreds(ctx context.Context, args ClientCredentials) (Result, error) { | ||
u, err := url.Parse("https://" + args.Domain) | ||
if err != nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any way we can support the use case mentioned in #556 (only X scopes when scripting)? Note that as we add support for more and more resources, the number of scopes requested initially will keep going up. This is probably fine for human usage, but for machine usage we'll probably want to find an alternative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely. However, that is a separate task. This PR only pertains to scoping with respect to device code flow, whereas #556 is concerned with client credentials. I think that work is better suited for its own PR.