Skip to content

Commit 3fb89b8

Browse files
authored
Rework authentication UI + OAuth support (#90)
* Init Oauth token authentication Add tooltip for all settings Rewrite the datasource configuration UI Support non encoded private key in the datasource configuration. * Optimize images * Implement OAuth flow * Update go.mod and go.sum * Init Oauth token authentication Add tooltip for all settings Rewrite the datasource configuration UI Support non encoded private key in the datasource configuration. * Optimize images * Implement OAuth flow * Add clientId & clientSecret * dep: Add oauth2 dependencies * chore: upgrade go dependencies * feature: add oAuth flow to connection validation Signed-off-by: devnied <[email protected]> * chore: update documentation Signed-off-by: devnied <[email protected]> * feat: Rework authentication secret parameters Signed-off-by: Julien Millau <[email protected]> * chore: rework package and add unit tests Signed-off-by: Julien Millau <[email protected]> * chore: Add unit tests for Oauth methods Signed-off-by: Julien Millau <[email protected]> * chore: Fix sonar violations Signed-off-by: Julien Millau <[email protected]> * Use AppUrl constant Signed-off-by: devnied <[email protected]> * Add support of client credential Oauth flow Signed-off-by: devnied <[email protected]> * Update dependencies Signed-off-by: devnied <[email protected]> * refactor: streamline health check error handling and validation logic Signed-off-by: Julien Millau <[email protected]> * refactor: remove unreachable code Signed-off-by: Julien Millau <[email protected]> * Update changelog Signed-off-by: Julien Millau <[email protected]> --------- Signed-off-by: Julien Millau <[email protected]>
1 parent be73d4f commit 3fb89b8

29 files changed

+1243
-610
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
- name: Setup Go environment
5050
uses: actions/setup-go@v5
5151
with:
52-
go-version: "1.22"
52+
go-version: "1.23"
5353

5454
- name: Test backend
5555
uses: magefile/mage-action@v3

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Setup Go environment
2121
uses: actions/setup-go@v5
2222
with:
23-
go-version: "1.22"
23+
go-version: "1.23"
2424

2525
- name: Get yarn cache directory path
2626
id: yarn-cache-dir-path

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ e2e-results/
3333

3434
.DS_Store
3535
.bra.toml
36-
36+
.eslintcache

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@
44

55
### ⭐ Added
66
- Add a query tag that includes relevant Grafana context information.
7+
- Add support of OAuth authentication.
78

89
### 🐞 Bug Fixes
910
- Source query variables are replaced with hardcoded values in the query editor UI.
1011

12+
### 🔨 Changed
13+
- Rewrite the datasource configuration UI (ease authentication selection).
14+
- Support non encoded private key in the datasource configuration.
15+
- Update deprecated APIs
16+
- Upgrade grafana-plugin-sdk-go to version v0.265.0.
17+
- Upgrade gosnowflake to version v1.13.0.
18+
- Upgrade go to version 1.23.
19+
1120
## 1.9.1
1221

1322
### 🔨 Changed

README.md

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,15 @@ docker run -d \
4242
grafana/grafana
4343
```
4444

45+
> [!NOTE]
46+
> Please refer to the documentation for more details.
47+
https://grafana.com/docs/grafana/latest/administration/plugin-management/#allow-unsigned-plugins
48+
4549
3. Restart grafana
50+
Restart the Grafana server to apply the changes:
51+
``` bash
52+
service grafana-server restart
53+
```
4654

4755
#### Configure the Datasource
4856

@@ -57,17 +65,43 @@ Add your authentication and [configuration details](https://docs.snowflake.com/e
5765

5866
Available configuration fields are as follows:
5967

60-
Name | Description
61-
------------------------- | ------------
62-
Account Name | Specifies the full name of your account (provided by Snowflake)
63-
Username | Specifies the login name of the user for the connection.
64-
Password | Specifies the password for the specified user.
65-
Private key | Specifies the the private key. Must be encoded in base 64 URL encoded pkcs8.<br/>**Command :**<br/> `egrep -v '^(-----BEGIN PRIVATE KEY\|-----END PRIVATE KEY)' rsa_key.p8 \| tr -d '\n' \| sed 's/+/-/g; s/\//_/g' > rsa_key_urlbase64.p8`
66-
Role (Optional) | Specifies the default access control role to use in the Snowflake session initiated by Grafana.
67-
Warehouse (Optional) | Specifies the virtual warehouse to use once connected.
68-
Database (Optional) | Specifies the default database to use once connected.
69-
Schema (Optional) | Specifies the default schema to use for the specified database once connected.
70-
Extra Options (Optional) | Specifies a series of one or more parameters, in the form of `<param>=<value>`, with each parameter separated by the ampersand character (&), and no spaces anywhere in the connection string.
68+
| Name | Description |
69+
|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
70+
| Account Name | Specifies the full name of your account (provided by Snowflake) |
71+
| Username | Specifies the login name of the user for the connection. |
72+
| Password | Specifies the password for the specified user. |
73+
| Private key | Specifies the private key. |
74+
| Client Id | Specifies the Oauth client ID. |
75+
| Client Secret | Specifies the Oauth client Secret. |
76+
| Token Endpoint | Specifies the Oauth Token endpoint. |
77+
| Role (Optional) | Specifies the default access control role to use in the Snowflake session initiated by Grafana. With Oauth, it's used to limit the access token to a single role that the user can consent to for the session. |
78+
| Warehouse (Optional) | Specifies the virtual warehouse to use once connected. |
79+
| Database (Optional) | Specifies the default database to use once connected. |
80+
| Schema (Optional) | Specifies the default schema to use for the specified database once connected. |
81+
| Extra Options (Optional) | Specifies a series of one or more parameters, in the form of `<param>=<value>`, with each parameter separated by the ampersand character (&), and no spaces anywhere in the connection string. |
82+
83+
**External OAuth authentication**
84+
85+
> [!NOTE]
86+
> Snowflake oauth authentication is not supported without external service (like Okta, Azure Entra, Keycloak ...) because of the lack of support for oauth Client credentials flow in snowflake.
87+
https://docs.snowflake.com/en/user-guide/oauth-intro
88+
89+
The plugin supports OAuth authentication with snowflake only with external_service.<br/>
90+
To use OAuth, you need to create an [external OAuth](https://docs.snowflake.com/en/user-guide/oauth-ext-custom) integration in your Snowflake account.
91+
```sql
92+
-- Create a security integration for external OAuth flow
93+
CREATE OR REPLACE SECURITY INTEGRATION OAUTH_INTEGRATION
94+
TYPE = EXTERNAL_OAUTH
95+
ENABLED = TRUE
96+
EXTERNAL_OAUTH_TYPE = CUSTOM
97+
EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE = 'scope'
98+
EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'name'
99+
EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'login_name'
100+
EXTERNAL_OAUTH_ALLOWED_ROLES_LIST = ('<xxxxx>')
101+
EXTERNAL_OAUTH_AUDIENCE_LIST =('https://xxxxx')
102+
EXTERNAL_OAUTH_RSA_PUBLIC_KEY = 'MIIBIj'
103+
EXTERNAL_OAUTH_ISSUER = 'https://xxxxx';
104+
```
71105

72106
#### Supported Macros
73107

@@ -108,6 +142,9 @@ For Time series query:
108142

109143
![Query editor](img/query.png)
110144

145+
> [!CAUTION]
146+
> This plugin cannot identify malicious code in queries executed on Snowflake and assumes no responsibility for their execution. As a precaution, use a ROLE with minimal privileges, configured to grant read-only access
147+
111148
##### Query Variables
112149

113150
You can use query variable in your Snowflake queries by using [variable syntax](https://grafana.com/docs/grafana/latest/dashboards/variables/variable-syntax/).<br/>
@@ -187,13 +224,21 @@ GROUP BY
187224
Annotations allow you to overlay events on a graph.
188225
To create an annotation, in the dashboard settings click "Annotations", and "New".
189226

227+
#### Oauth Configuration
228+
229+
To use Oauth, you need to create an Oauth custom integration in your Snowflake account.<
230+
You can follow the steps in the [Snowflake documentation](https://docs.snowflake.com/en/user-guide/oauth-custom).
231+
190232
## Caching
191233
### Snowflake caching
192234

193235
Snowflake caches queries with the same footprint / hash in its own query-cache. Since a Grafana query mostly has a now() component the cache will never be used.
194236
To get more queries with the same hash use the two macros `$__timeRoundFrom(d)` and `$__timeRoundTo(d)` to create wider truncated timestamps. This is no problem for timeseries charts. Grafana cuts it's x-Axis to the selected dashboard time window. If a table is displayed the whole result will be presented and it could be slightly out of the time window.\
195237
More info about snowflake-side caching: https://docs.snowflake.com/en/user-guide/querying-persisted-results#retrieval-optimization
196238

239+
## Supported Grafana Versions
240+
This plugin supports only version with [Active Support from Grafana](https://grafana.com/docs/grafana/next/upgrade-guide/when-to-upgrade/?pg=blog&plcmt=body-txt#what-to-know-about-version-support).
241+
197242
## Development
198243

199244
The snowflake datasource is a data source backend plugin composed of both frontend and backend components.

go.mod

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
module github.com/michelin/snowflake-grafana-datasource
22

3-
go 1.22
3+
go 1.23.5
44

5-
toolchain go1.22.0
5+
toolchain go1.23.6
66

77
require (
88
github.com/DATA-DOG/go-sqlmock v1.5.2
9-
github.com/grafana/grafana-plugin-sdk-go v0.260.1
9+
github.com/grafana/grafana-plugin-sdk-go v0.265.0
1010
github.com/snowflakedb/gosnowflake v1.13.0
1111
github.com/stretchr/testify v1.10.0
12+
golang.org/x/oauth2 v0.26.0
1213
)
1314

1415
require (
@@ -19,7 +20,7 @@ require (
1920
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect
2021
github.com/BurntSushi/toml v1.4.0 // indirect
2122
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
22-
github.com/apache/arrow/go/v15 v15.0.2 // indirect
23+
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 // indirect
2324
github.com/apache/arrow/go/v16 v16.0.0 // indirect
2425
github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
2526
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
@@ -43,38 +44,37 @@ require (
4344
github.com/danieljoos/wincred v1.1.2 // indirect
4445
github.com/davecgh/go-spew v1.1.1 // indirect
4546
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
46-
github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 // indirect
47+
github.com/elazarl/goproxy v1.7.0 // indirect
4748
github.com/fatih/color v1.15.0 // indirect
4849
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
49-
github.com/getkin/kin-openapi v0.128.0 // indirect
50+
github.com/getkin/kin-openapi v0.129.0 // indirect
5051
github.com/go-logr/logr v1.4.2 // indirect
5152
github.com/go-logr/stdr v1.2.2 // indirect
5253
github.com/go-openapi/jsonpointer v0.21.0 // indirect
5354
github.com/go-openapi/swag v0.23.0 // indirect
54-
github.com/goccy/go-json v0.10.2 // indirect
55+
github.com/goccy/go-json v0.10.4 // indirect
5556
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
5657
github.com/gogo/protobuf v1.3.2 // indirect
5758
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
5859
github.com/golang/protobuf v1.5.4 // indirect
5960
github.com/google/flatbuffers v24.3.25+incompatible // indirect
6061
github.com/google/go-cmp v0.6.0 // indirect
6162
github.com/google/uuid v1.6.0 // indirect
62-
github.com/gorilla/mux v1.8.1 // indirect
63+
github.com/gorilla/mux v1.8.0 // indirect
6364
github.com/grafana/otel-profiling-go v0.5.1 // indirect
6465
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
6566
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
66-
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
67-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
67+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect
68+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
6869
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
6970
github.com/hashicorp/go-hclog v1.6.3 // indirect
70-
github.com/hashicorp/go-plugin v1.6.2 // indirect
71+
github.com/hashicorp/go-plugin v1.6.3 // indirect
7172
github.com/hashicorp/yamux v0.1.1 // indirect
72-
github.com/invopop/yaml v0.3.1 // indirect
7373
github.com/jmespath/go-jmespath v0.4.0 // indirect
7474
github.com/josharian/intern v1.0.0 // indirect
7575
github.com/json-iterator/go v1.1.12 // indirect
76-
github.com/klauspost/compress v1.17.9 // indirect
77-
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
76+
github.com/klauspost/compress v1.17.11 // indirect
77+
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
7878
github.com/magefile/mage v1.15.0 // indirect
7979
github.com/mailru/easyjson v0.7.7 // indirect
8080
github.com/mattetti/filebuffer v1.0.1 // indirect
@@ -86,15 +86,17 @@ require (
8686
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
8787
github.com/mtibben/percent v0.2.1 // indirect
8888
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
89-
github.com/oklog/run v1.1.0 // indirect
89+
github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 // indirect
90+
github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 // indirect
91+
github.com/oklog/run v1.0.0 // indirect
9092
github.com/olekukonko/tablewriter v0.0.5 // indirect
9193
github.com/perimeterx/marshmallow v1.1.5 // indirect
9294
github.com/pierrec/lz4/v4 v4.1.21 // indirect
9395
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
9496
github.com/pmezard/go-difflib v1.0.0 // indirect
9597
github.com/prometheus/client_golang v1.20.5 // indirect
9698
github.com/prometheus/client_model v0.6.1 // indirect
97-
github.com/prometheus/common v0.60.1 // indirect
99+
github.com/prometheus/common v0.62.0 // indirect
98100
github.com/prometheus/procfs v0.15.1 // indirect
99101
github.com/russross/blackfriday/v2 v2.1.0 // indirect
100102
github.com/sirupsen/logrus v1.9.3 // indirect
@@ -103,31 +105,32 @@ require (
103105
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 // indirect
104106
github.com/urfave/cli v1.22.16 // indirect
105107
github.com/zeebo/xxh3 v1.0.2 // indirect
106-
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // indirect
107-
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 // indirect
108-
go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 // indirect
109-
go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 // indirect
110-
go.opentelemetry.io/otel v1.32.0 // indirect
111-
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect
112-
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect
113-
go.opentelemetry.io/otel/metric v1.32.0 // indirect
114-
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
115-
go.opentelemetry.io/otel/trace v1.32.0 // indirect
116-
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
117-
golang.org/x/crypto v0.31.0 // indirect
118-
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
119-
golang.org/x/mod v0.17.0 // indirect
120-
golang.org/x/net v0.33.0 // indirect
121-
golang.org/x/sync v0.10.0 // indirect
122-
golang.org/x/sys v0.28.0 // indirect
123-
golang.org/x/term v0.27.0 // indirect
108+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
109+
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
110+
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.59.0 // indirect
111+
go.opentelemetry.io/contrib/propagators/jaeger v1.34.0 // indirect
112+
go.opentelemetry.io/contrib/samplers/jaegerremote v0.28.0 // indirect
113+
go.opentelemetry.io/otel v1.34.0 // indirect
114+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect
115+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect
116+
go.opentelemetry.io/otel/metric v1.34.0 // indirect
117+
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
118+
go.opentelemetry.io/otel/trace v1.34.0 // indirect
119+
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
120+
golang.org/x/crypto v0.32.0 // indirect
121+
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
122+
golang.org/x/mod v0.22.0 // indirect
123+
golang.org/x/net v0.34.0 // indirect
124+
golang.org/x/sync v0.11.0 // indirect
125+
golang.org/x/sys v0.29.0 // indirect
126+
golang.org/x/term v0.28.0 // indirect
124127
golang.org/x/text v0.21.0 // indirect
125-
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
128+
golang.org/x/tools v0.28.0 // indirect
126129
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
127-
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
128-
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
129-
google.golang.org/grpc v1.67.1 // indirect
130-
google.golang.org/protobuf v1.35.2 // indirect
130+
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
131+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
132+
google.golang.org/grpc v1.70.0 // indirect
133+
google.golang.org/protobuf v1.36.4 // indirect
131134
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
132135
gopkg.in/yaml.v3 v3.0.1 // indirect
133136
)

0 commit comments

Comments
 (0)