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

✨ Feat: add oauth scopes configuration option #100

Merged
merged 3 commits into from
Nov 16, 2024
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
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## 1.3.3
## 1.3.4

- Feature: Add OAuth Scopes Configuration

---

### 1.3.3

- Feature: Add additional connection & query editor config options

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ grafana/grafana

To configure the plugin use the values provided under JDBC/ODBC in the advanced options of the Databricks Cluster (or SQL Warehouse) and the the Credentials according to the chosen Authentication Method.

You can either authenticate the plugin using a [Personal Access Token (PAT)](https://docs.databricks.com/en/dev-tools/auth/pat.html), via [Databricks M2M OAuth](https://docs.databricks.com/en/dev-tools/auth/oauth-m2m.html) using a Service Principal Client ID and Client Secret or by using an external OAuth Client Credential Endpoint which returns a Databricks token (the OAuth endpoint should implement the default [OAuth Client Credential Grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4))
You can either authenticate the plugin using a [Personal Access Token (PAT)](https://docs.databricks.com/en/dev-tools/auth/pat.html), via [Databricks M2M OAuth](https://docs.databricks.com/en/dev-tools/auth/oauth-m2m.html) using a Service Principal Client ID and Client Secret or by using an external OAuth Client Credential Endpoint which returns a Databricks token (the OAuth endpoint should implement the default [OAuth Client Credential Grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)) i.e. Azure Entra (OAuth2 Endpoint `https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token` & Scope `2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default`).

![img_1.png](img/config_editor.png)

Expand All @@ -75,6 +75,7 @@ Available configuration fields are as follows:
| Client Secret | Databricks Service Principal Client Secret. (only if OAuth / OAuth2 is chosen as Auth Method) |
| Access Token | Personal Access Token for Databricks. (only if PAT is chosen as Auth Method) |
| OAuth2 Token Endpoint | URL of OAuth2 endpoint (only if OAuth2 Client Credentials Authentication is chosen as Auth Method) |
| OAuth2 Scopes | Comma separated list of OAuth2 scopes. (only if OAuth2 Client Credentials Authentication is chosen as Auth Method) |
| Min Interval (Default) | Min Interval default value for all queries. A lower limit for the interval. Recommended to be set to write frequency, for example `1m` if your data is written every minute. |
| Max Open | The maximum number of open connections to the database. (0 = unlimited) |
| Max Idle | The maximum number of idle connections to the database. (0 = no idle connections are retained) |
Expand Down Expand Up @@ -105,6 +106,7 @@ datasources:
authenticationMethod: dsn (=PAT) | m2m | oauth2_client_credentials
clientId: ...
externalCredentialsUrl: ...
oauthScopes: api,read
timeInterval: 1m
maxOpenConns: 0
maxIdleConns: 0
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mullerpeter-databricks-datasource",
"private": true,
"version": "1.3.3",
"version": "1.3.4",
"description": "Databricks SQL Connector",
"scripts": {
"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
Expand Down
5 changes: 4 additions & 1 deletion pkg/integrations/oauth2_client_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type oauth2ClientCredentials struct {
clientID string
clientSecret string
tokenUrl string
scopes []string
tokenSource oauth2.TokenSource
mx sync.Mutex
}
Expand All @@ -35,6 +36,7 @@ func (c *oauth2ClientCredentials) Authenticate(r *http.Request) error {
ClientID: c.clientID,
ClientSecret: c.clientSecret,
TokenURL: c.tokenUrl,
Scopes: c.scopes,
}

// Create context with 1m timeout to cancel token fetching
Expand All @@ -60,11 +62,12 @@ func (c *oauth2ClientCredentials) Authenticate(r *http.Request) error {

}

func NewOauth2ClientCredentials(clientID, clientSecret, tokenUrl string) auth.Authenticator {
func NewOauth2ClientCredentials(clientID, clientSecret, tokenUrl string, scopes []string) auth.Authenticator {
return &oauth2ClientCredentials{
clientID: clientID,
clientSecret: clientSecret,
tokenUrl: tokenUrl,
scopes: scopes,
tokenSource: nil,
mx: sync.Mutex{},
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type DatasourceSettings struct {
AuthenticationMethod string `json:"authenticationMethod"`
ClientId string `json:"clientId"`
ExternalCredentialsUrl string `json:"externalCredentialsUrl"`
OAuthScopes string `json:"oauthScopes"`
}

type ConnectionSettingsRawJson struct {
Expand Down Expand Up @@ -102,6 +103,7 @@ func NewSampleDatasource(_ context.Context, settings backend.DataSourceInstanceS
datasourceSettings.ClientId,
settings.DecryptedSecureJSONData["clientSecret"],
datasourceSettings.ExternalCredentialsUrl,
strings.Split(datasourceSettings.OAuthScopes, ","),
)
} else if datasourceSettings.AuthenticationMethod == "m2m" {
authenticator = m2m.NewAuthenticatorWithScopes(
Expand Down
26 changes: 18 additions & 8 deletions src/components/ConfigEditor/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,24 @@ export class ConfigEditor extends PureComponent<Props, State> {
/>
</InlineField>
{jsonData.authenticationMethod === 'oauth2_client_credentials' && (
<InlineField label="OAuth2 Token Endpoint" labelWidth={30} tooltip="HTTP URL to token endpoint">
<Input
value={jsonData.externalCredentialsUrl || ''}
placeholder="http://localhost:2020"
width={40}
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onValueChange(event, 'externalCredentialsUrl')}
/>
</InlineField>
<>
<InlineField label="OAuth2 Token Endpoint" labelWidth={30} tooltip="HTTP URL to token endpoint">
<Input
value={jsonData.externalCredentialsUrl || ''}
placeholder="http://localhost:2020"
width={40}
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onValueChange(event, 'externalCredentialsUrl')}
/>
</InlineField>
<InlineField label="OAuth2 Scopes" labelWidth={30} tooltip="Comma separated list of scopes (optional)">
<Input
value={jsonData.oauthScopes || ''}
width={40}
placeholder="api,read"
onChange={(event: ChangeEvent<HTMLInputElement>) => this.onValueChange(event, 'oauthScopes')}
/>
</InlineField>
</>
)}
{(jsonData.authenticationMethod === 'm2m' || jsonData.authenticationMethod === 'oauth2_client_credentials') ? (
<>
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface DatabricksDataSourceOptions extends SQLOptions {
authenticationMethod?: string;
clientId?: string;
externalCredentialsUrl?: string;
oauthScopes?: string;
retries?: string;
retryBackoff?: string;
maxRetryDuration?: string;
Expand Down
Loading