-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[Filebeat][httpjson] httpjson oauth2 authentication mechanism for salesforce events #29087
Changes from all commits
e2aab83
d38852d
7bbacd8
abfae0b
d30ac17
0c6f0ae
9bbf09d
1df0b01
54735fb
d4d21c1
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 |
---|---|---|
|
@@ -85,6 +85,19 @@ filebeat.inputs: | |
request.url: http://localhost | ||
---- | ||
|
||
["source","yaml",subs="attributes"] | ||
---- | ||
filebeat.inputs: | ||
- type: httpjson | ||
auth.oauth2: | ||
client.id: 12345678901234567890abcdef | ||
client.secret: abcdef12345678901234567890 | ||
token_url: http://localhost/oauth2/token | ||
user: [email protected] | ||
password: P@$$W0₹D | ||
request.url: http://localhost | ||
---- | ||
|
||
[[input-state]] | ||
==== Input state | ||
|
||
|
@@ -265,6 +278,22 @@ except if using `google` as provider. Required for providers: `default`, `azure` | |
The client secret used as part of the authentication flow. It is always required | ||
except if using `google` as provider. Required for providers: `default`, `azure`. | ||
|
||
[float] | ||
==== `auth.oauth2.user` | ||
|
||
The user used as part of the authentication flow. It is required for authentication | ||
- grant type password. It is only available for provider `default`. | ||
|
||
[float] | ||
==== `auth.oauth2.password` | ||
|
||
The password used as part of the authentication flow. It is required for authentication | ||
- grant type password. It is only available for provider `default`. | ||
|
||
NOTE: user and password are required for grant_type password. If user and | ||
password is not used then it will automatically use the `token_url` and | ||
`client credential` method. | ||
|
||
[float] | ||
==== `auth.oauth2.scopes` | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,9 @@ import ( | |
"github.com/elastic/beats/v7/libbeat/common" | ||
) | ||
|
||
// authStyleInParams sends the "client_id" and "client_secret" in the POST body as application/x-www-form-urlencoded parameters. | ||
const authStyleInParams = 1 | ||
|
||
type authConfig struct { | ||
Basic *basicAuthConfig `config:"basic"` | ||
OAuth2 *oAuth2Config `config:"oauth2"` | ||
|
@@ -83,9 +86,11 @@ type oAuth2Config struct { | |
ClientID string `config:"client.id"` | ||
ClientSecret string `config:"client.secret"` | ||
EndpointParams map[string][]string `config:"endpoint_params"` | ||
Password string `config:"password"` | ||
Provider oAuth2Provider `config:"provider"` | ||
Scopes []string `config:"scopes"` | ||
TokenURL string `config:"token_url"` | ||
User string `config:"user"` | ||
|
||
// google specific | ||
GoogleCredentialsFile string `config:"google.credentials_file"` | ||
|
@@ -103,20 +108,43 @@ func (o *oAuth2Config) isEnabled() bool { | |
return o != nil && (o.Enabled == nil || *o.Enabled) | ||
} | ||
|
||
// clientCredentialsGrant creates http client from token_url and client credentials | ||
func (o *oAuth2Config) clientCredentialsGrant(ctx context.Context, client *http.Client) *http.Client { | ||
creds := clientcredentials.Config{ | ||
ClientID: o.ClientID, | ||
ClientSecret: o.ClientSecret, | ||
TokenURL: o.getTokenURL(), | ||
Scopes: o.Scopes, | ||
EndpointParams: o.getEndpointParams(), | ||
} | ||
return creds.Client(ctx) | ||
} | ||
|
||
// Client wraps the given http.Client and returns a new one that will use the oauth authentication. | ||
func (o *oAuth2Config) client(ctx context.Context, client *http.Client) (*http.Client, error) { | ||
ctx = context.WithValue(ctx, oauth2.HTTPClient, client) | ||
|
||
switch o.getProvider() { | ||
case oAuth2ProviderAzure, oAuth2ProviderDefault: | ||
creds := clientcredentials.Config{ | ||
ClientID: o.ClientID, | ||
ClientSecret: o.ClientSecret, | ||
TokenURL: o.getTokenURL(), | ||
Scopes: o.Scopes, | ||
EndpointParams: o.getEndpointParams(), | ||
case oAuth2ProviderDefault: | ||
if o.User != "" || o.Password != "" { | ||
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. Is it also valid for Azure? Do you think it's worth considering introducing another type: 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. I am not sure but they do support username-password authentication here. 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. Do you think it's worth focusing on the oauth2ProviderSalesforce provider now? 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. I think we have another option.
What do you think if we do this? 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. RFC defines it (Resource Owner Password Credentials Grant), so I don't see a reason why don't apply it also here. Feel free to modify the source code. |
||
conf := &oauth2.Config{ | ||
ClientID: o.ClientID, | ||
ClientSecret: o.ClientSecret, | ||
mtojek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Endpoint: oauth2.Endpoint{ | ||
TokenURL: o.TokenURL, | ||
AuthStyle: authStyleInParams, | ||
}, | ||
} | ||
token, err := conf.PasswordCredentialsToken(ctx, o.User, o.Password) | ||
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. Any ideas for covering this logic with unit tests? 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. as an idea, if we want to test this bit in isolation, could get extracted to its own function and validate the resulting token |
||
if err != nil { | ||
return nil, fmt.Errorf("oauth2 client: error loading credentials using user and password: %w", err) | ||
} | ||
return conf.Client(ctx, token), nil | ||
} else { | ||
return o.clientCredentialsGrant(ctx, client), nil | ||
} | ||
return creds.Client(ctx), nil | ||
case oAuth2ProviderAzure: | ||
return o.clientCredentialsGrant(ctx, client), nil | ||
case oAuth2ProviderGoogle: | ||
if o.GoogleJWTFile != "" { | ||
cfg, err := google.JWTConfigFromJSON(o.GoogleCredentialsJSON, o.Scopes...) | ||
|
@@ -184,6 +212,9 @@ func (o *oAuth2Config) Validate() error { | |
if o.TokenURL == "" || o.ClientID == "" || o.ClientSecret == "" { | ||
return errors.New("both token_url and client credentials must be provided") | ||
} | ||
if (o.User != "" && o.Password == "") || (o.User == "" && o.Password != "") { | ||
mtojek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return errors.New("both user and password credentials must be provided") | ||
} | ||
default: | ||
return fmt.Errorf("unknown provider %q", o.getProvider()) | ||
} | ||
|
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.
Would be nice to add a brief comment in here to know what is used for, and maybe declare it local to where it is going to be used if not expected to be reused anymore.
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.
Sure, Got it.
Thanks
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.
Done. added one liner describing the context.