Azure: Use SSO settings in plugin context (#112058)

* Bump grafana-azure-sdk-go

* Set override values

* Add Azure settings helper covering SSO cases

* Ensure Azure settings are correctly created

- Add mock for sso settings service
- Add tests
- Update wire

* Minor improvements

* Test updates

* Move fake implementation

* add interface to limit leakage

* rename

* work sync

* Fix wire

* Add fake provider

* Update tests

* Actually fix the workspace

* More go dependency fixes

* Update tests

* Update workspace, again

* Add missing tests

* Fix dependencies

* These dependencies..

* More dependency things

* Okay now dependencies really are fixed

* Lint

* Update pkg/services/pluginsintegration/pluginconfig/request.go

Co-authored-by: Misi <mgyongyosi@users.noreply.github.com>

---------

Co-authored-by: Will Browne <wbrowne@tcd.ie>
Co-authored-by: Misi <mgyongyosi@users.noreply.github.com>
This commit is contained in:
Andreas Christou
2025-10-10 11:46:26 +01:00
committed by GitHub
co-authored by Misi Will Browne
parent 59459560c2
commit fa9d6be255
15 changed files with 652 additions and 75 deletions
+5 -5
View File
@@ -13,8 +13,8 @@ require (
filippo.io/age v1.2.1 // @grafana/identity-access-team
github.com/1NCE-GmbH/grpc-go-pool v0.0.0-20231117122434-2a5bb974daa2 // @grafana/grafana-search-and-storage
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // @grafana/partner-datasources
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // @grafana/identity-access-team
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // @grafana/grafana-backend-group
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // @grafana/identity-access-team
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // @grafana/grafana-backend-group
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // @grafana/grafana-backend-group
github.com/Azure/azure-storage-blob-go v0.15.0 // @grafana/grafana-backend-group
github.com/Azure/go-autorest/autorest v0.11.29 // @grafana/grafana-backend-group
@@ -99,7 +99,7 @@ require (
github.com/grafana/grafana-app-sdk v0.46.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk/logging v0.45.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-aws-sdk v1.2.0 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 // @grafana/partner-datasources
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // @grafana/partner-datasources
github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 // @grafana/grafana-operator-experience-squad
github.com/grafana/grafana-google-sdk-go v0.4.2 // @grafana/partner-datasources
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group
@@ -296,7 +296,7 @@ require (
cloud.google.com/go/monitoring v1.24.2 // indirect
cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@@ -306,7 +306,7 @@ require (
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
github.com/FZambia/eagle v0.2.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
+10 -10
View File
@@ -648,14 +648,14 @@ github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl
github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 h1:wL5IEG5zb7BVv1Kv0Xm92orq+5hB5Nipn3B5tn4Rqfk=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE=
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
@@ -703,8 +703,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb h1:ZVN4Iat3runWOFLaBCDVU5a9X/XikSRBosye++6gojw=
github.com/Bose/minisentinel v0.0.0-20200130220412-917c5a9223bb/go.mod h1:WsAABbY4HQBgd3mGuG4KMNTbHJCPvx9IVBHzysbknss=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -1611,8 +1611,8 @@ github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xu
github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA=
github.com/grafana/grafana-aws-sdk v1.2.0 h1:LLR4/g91WBuCRwm2cbWfCREq565+GxIFe08nqqIcIuw=
github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A=
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 h1:0TYrkzAc3u0HX+9GK86cGrLTUAcmQfl3/LEB3tL+SOA=
github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0/go.mod h1:H9sVh9A4yg5egMGZeh0mifxT1Q/uqwKe1LBjBJU6pN8=
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk=
github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1/go.mod h1:Oi4anANlCuTCc66jCyqIzfVbgLXFll8Wja+Y4vfANlc=
github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI=
github.com/grafana/grafana-cloud-migration-snapshot v1.9.0/go.mod h1:nOHgq4Oa829qmBKA5KIXw5Ipo3rhLs0d6A8UI9Nw8Zk=
github.com/grafana/grafana-google-sdk-go v0.4.2 h1:F44hQF1y6UVJhlJPi+Mz+GCJsioVgezEgPMMEQbUZRo=
+5
View File
@@ -1224,6 +1224,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kevinmbeaulieu/eq-go v1.0.0 h1:AQgYHURDOmnVJ62jnEk0W/7yFKEn+Lv8RHN6t7mB0Zo=
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a h1:K0EAzgzEQHW4Y5lxrmvPMltmlRDzlhLfGmots9EHUTI=
github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8=
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY=
@@ -1336,6 +1338,7 @@ github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I=
@@ -1453,6 +1456,7 @@ github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHf
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs=
github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM=
@@ -1995,6 +1999,7 @@ golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+2 -3
View File
@@ -18,8 +18,8 @@ require (
)
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/apache/arrow-go/v18 v18.4.0 // indirect
github.com/aws/aws-sdk-go v1.55.7 // indirect
@@ -48,7 +48,6 @@ require (
github.com/goccy/go-json v0.10.5 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/gnostic-models v0.7.0 // indirect
+8 -8
View File
@@ -5,14 +5,14 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 h1:wL5IEG5zb7BVv1Kv0Xm92orq+5hB5Nipn3B5tn4Rqfk=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+11 -8
View File
@@ -188,6 +188,7 @@ import (
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginexternal"
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
service6 "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/renderer"
@@ -342,7 +343,10 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
hooksService := hooks.ProvideService()
ossLicensingService := licensing.ProvideService(cfg, hooksService)
licensingService := licensing2.ProvideLicensing(cfg, ossLicensingService)
envVarsProvider := pluginconfig.NewEnvVarsProvider(pluginInstanceCfg, licensingService)
registerer := metrics.ProvideRegisterer()
ssosettingsimplService := ssosettingsimpl.ProvideService(cfg, sqlStore, accessControl, routeRegisterImpl, featureToggles, secretsService, usageStats, registerer, ossImpl, ossLicensingService)
defaultSettingsProvider := pluginsso.ProvideDefaultSettingsProvider(ssosettingsimplService)
envVarsProvider := pluginconfig.NewEnvVarsProvider(pluginInstanceCfg, licensingService, defaultSettingsProvider)
inMemory := registry.ProvideService()
rendererManager, err := renderer.ProvideService(pluginManagementCfg, envVarsProvider, inMemory, tracingService)
if err != nil {
@@ -424,7 +428,6 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
}
publicDashboardStoreImpl := database3.ProvideStore(sqlStore, cfg, featureToggles)
publicDashboardServiceWrapperImpl := service3.ProvideServiceWrapper(publicDashboardStoreImpl)
registerer := metrics.ProvideRegisterer()
apikeyService, err := apikeyimpl.ProvideService(sqlStore, cfg, quotaService)
if err != nil {
return nil, err
@@ -559,7 +562,6 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
pluginService := service7.ProvideDashboardPluginService(featureToggles, dashboardServiceImpl)
service14 := service8.ProvideService(fileStoreManager, pluginService)
orgRoleMapper := connectors.ProvideOrgRoleMapper(cfg, orgService)
ssosettingsimplService := ssosettingsimpl.ProvideService(cfg, sqlStore, accessControl, routeRegisterImpl, featureToggles, secretsService, usageStats, registerer, ossImpl, ossLicensingService)
socialService := socialimpl.ProvideService(cfg, featureToggles, usageStats, bundleregistryService, remoteCache, orgRoleMapper, ssosettingsimplService)
loginStore := authinfoimpl.ProvideStore(sqlStore, secretsService)
authinfoimplService := authinfoimpl.ProvideService(loginStore, remoteCache, secretsService)
@@ -599,7 +601,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
return nil, err
}
datasourcePermissionsService := ossaccesscontrol.ProvideDatasourcePermissionsService(cfg, featureToggles, sqlStore)
requestConfigProvider := pluginconfig.NewRequestConfigProvider(pluginInstanceCfg)
requestConfigProvider := pluginconfig.NewRequestConfigProvider(pluginInstanceCfg, defaultSettingsProvider)
baseProvider := plugincontext.ProvideBaseService(cfg, requestConfigProvider)
service15, err := service9.ProvideService(sqlStore, secretsService, secretsKVStore, cfg, featureToggles, accessControl, datasourcePermissionsService, quotaService, pluginstoreService, middlewareHandler, baseProvider)
if err != nil {
@@ -943,7 +945,10 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
hooksService := hooks.ProvideService()
ossLicensingService := licensing.ProvideService(cfg, hooksService)
licensingService := licensing2.ProvideLicensing(cfg, ossLicensingService)
envVarsProvider := pluginconfig.NewEnvVarsProvider(pluginInstanceCfg, licensingService)
registerer := metrics.ProvideRegistererForTest()
ssosettingsimplService := ssosettingsimpl.ProvideService(cfg, sqlStore, accessControl, routeRegisterImpl, featureToggles, secretsService, usageStats, registerer, ossImpl, ossLicensingService)
defaultSettingsProvider := pluginsso.ProvideDefaultSettingsProvider(ssosettingsimplService)
envVarsProvider := pluginconfig.NewEnvVarsProvider(pluginInstanceCfg, licensingService, defaultSettingsProvider)
inMemory := registry.ProvideService()
rendererManager, err := renderer.ProvideService(pluginManagementCfg, envVarsProvider, inMemory, tracingService)
if err != nil {
@@ -1025,7 +1030,6 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
}
publicDashboardStoreImpl := database3.ProvideStore(sqlStore, cfg, featureToggles)
publicDashboardServiceWrapperImpl := service3.ProvideServiceWrapper(publicDashboardStoreImpl)
registerer := metrics.ProvideRegistererForTest()
apikeyService, err := apikeyimpl.ProvideService(sqlStore, cfg, quotaService)
if err != nil {
return nil, err
@@ -1195,7 +1199,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
return nil, err
}
datasourcePermissionsService := ossaccesscontrol.ProvideDatasourcePermissionsService(cfg, featureToggles, sqlStore)
requestConfigProvider := pluginconfig.NewRequestConfigProvider(pluginInstanceCfg)
requestConfigProvider := pluginconfig.NewRequestConfigProvider(pluginInstanceCfg, defaultSettingsProvider)
baseProvider := plugincontext.ProvideBaseService(cfg, requestConfigProvider)
service15, err := service9.ProvideService(sqlStore, secretsService, secretsKVStore, cfg, featureToggles, accessControl, datasourcePermissionsService, quotaService, pluginstoreService, middlewareHandler, baseProvider)
if err != nil {
@@ -1227,7 +1231,6 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
return nil, err
}
orgRoleMapper := connectors.ProvideOrgRoleMapper(cfg, orgService)
ssosettingsimplService := ssosettingsimpl.ProvideService(cfg, sqlStore, accessControl, routeRegisterImpl, featureToggles, secretsService, usageStats, registerer, ossImpl, ossLicensingService)
socialService := socialimpl.ProvideService(cfg, featureToggles, usageStats, bundleregistryService, remoteCache, orgRoleMapper, ssosettingsimplService)
loginStore := authinfoimpl.ProvideStore(sqlStore, secretsService)
authinfoimplService := authinfoimpl.ProvideService(loginStore, remoteCache, secretsService)
@@ -0,0 +1,66 @@
package pluginconfig
import (
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
)
// mergeAzureSettings merges the Azure AD settings from the SSO settings DB with the Azure AD settings from the config.
// Azure AD settings can be changed via the UI or SSO settings API
// They can also be overridden in the [azure] config section
// The order of precedence is:
// 1. [azure] config section (if the override flag is set)
// 2. SSO settings from the DB (if they exist)
// 3. [auth.azuread] config section (if enabled)
func mergeAzureSettings(currSettings *azsettings.AzureSettings, azureAdSettings *pluginsso.Settings) *azsettings.AzureSettings {
if azureAdSettings != nil {
settings := azureAdSettings.Values
tokenEndpointSettings := currSettings.UserIdentityTokenEndpoint
if tokenEndpointSettings == nil {
tokenEndpointSettings = &azsettings.TokenEndpointSettings{}
currSettings.UserIdentityTokenEndpoint = tokenEndpointSettings
}
tokenUrl, ok := settings["token_url"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.TokenUrlOverride {
currSettings.UserIdentityTokenEndpoint.TokenUrl = tokenUrl
}
}
clientAuth, ok := settings["client_authentication"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.ClientAuthenticationOverride {
if clientAuth != "none" {
currSettings.UserIdentityTokenEndpoint.ClientAuthentication = clientAuth
}
}
}
clientId, ok := settings["client_id"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.ClientIdOverride {
currSettings.UserIdentityTokenEndpoint.ClientId = clientId
}
}
clientSecret, ok := settings["client_secret"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.ClientSecretOverride {
currSettings.UserIdentityTokenEndpoint.ClientSecret = clientSecret
}
}
managedIdentityClientId, ok := settings["managed_identity_client_id"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.ManagedIdentityClientIdOverride {
currSettings.UserIdentityTokenEndpoint.ManagedIdentityClientId = managedIdentityClientId
}
}
federatedCredentialAudience, ok := settings["federated_credential_audience"].(string)
if ok {
if !currSettings.UserIdentityTokenEndpoint.FederatedCredentialAudienceOverride {
currSettings.UserIdentityTokenEndpoint.FederatedCredentialAudience = federatedCredentialAudience
}
}
}
return currSettings
}
@@ -0,0 +1,197 @@
package pluginconfig
import (
"testing"
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetAzureSettings(t *testing.T) {
t.Run("no Azure settings input", func(t *testing.T) {
result := mergeAzureSettings(nil, nil)
assert.Nil(t, result)
})
t.Run("no SSO settings or override settings", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "original-token-url",
ClientAuthentication: "original-auth",
ClientId: "original-client-id",
ClientSecret: "original-client-secret",
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
assert.Equal(t, "original-token-url", result.UserIdentityTokenEndpoint.TokenUrl)
assert.Equal(t, "original-auth", result.UserIdentityTokenEndpoint.ClientAuthentication)
assert.Equal(t, "original-client-id", result.UserIdentityTokenEndpoint.ClientId)
assert.Equal(t, "original-client-secret", result.UserIdentityTokenEndpoint.ClientSecret)
})
t.Run("with SSO settings but no overrides", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "original-token-url",
ClientAuthentication: "original-auth",
ClientId: "original-client-id",
ClientSecret: "original-client-secret",
ManagedIdentityClientId: "original-managed-id",
FederatedCredentialAudience: "original-audience",
TokenUrlOverride: false,
ClientAuthenticationOverride: false,
ClientIdOverride: false,
ClientSecretOverride: false,
ManagedIdentityClientIdOverride: false,
FederatedCredentialAudienceOverride: false,
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{
"token_url": "sso-token-url",
"client_authentication": "sso-auth",
"client_id": "sso-client-id",
"client_secret": "sso-client-secret",
"managed_identity_client_id": "sso-managed-id",
"federated_credential_audience": "sso-audience",
},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
assert.Equal(t, "sso-token-url", result.UserIdentityTokenEndpoint.TokenUrl)
assert.Equal(t, "sso-auth", result.UserIdentityTokenEndpoint.ClientAuthentication)
assert.Equal(t, "sso-client-id", result.UserIdentityTokenEndpoint.ClientId)
assert.Equal(t, "sso-client-secret", result.UserIdentityTokenEndpoint.ClientSecret)
assert.Equal(t, "sso-managed-id", result.UserIdentityTokenEndpoint.ManagedIdentityClientId)
assert.Equal(t, "sso-audience", result.UserIdentityTokenEndpoint.FederatedCredentialAudience)
})
t.Run("with both overrides and SSO settings", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "override-token-url",
ClientAuthentication: "override-auth",
ClientId: "override-client-id",
ClientSecret: "override-client-secret",
ManagedIdentityClientId: "override-managed-id",
FederatedCredentialAudience: "override-audience",
TokenUrlOverride: true,
ClientAuthenticationOverride: true,
ClientIdOverride: true,
ClientSecretOverride: true,
ManagedIdentityClientIdOverride: true,
FederatedCredentialAudienceOverride: true,
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{
"token_url": "sso-token-url",
"client_authentication": "sso-auth",
"client_id": "sso-client-id",
"client_secret": "sso-client-secret",
"managed_identity_client_id": "sso-managed-id",
"federated_credential_audience": "sso-audience",
},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
// Should keep override values, not SSO values
assert.Equal(t, "override-token-url", result.UserIdentityTokenEndpoint.TokenUrl)
assert.Equal(t, "override-auth", result.UserIdentityTokenEndpoint.ClientAuthentication)
assert.Equal(t, "override-client-id", result.UserIdentityTokenEndpoint.ClientId)
assert.Equal(t, "override-client-secret", result.UserIdentityTokenEndpoint.ClientSecret)
assert.Equal(t, "override-managed-id", result.UserIdentityTokenEndpoint.ManagedIdentityClientId)
assert.Equal(t, "override-audience", result.UserIdentityTokenEndpoint.FederatedCredentialAudience)
})
t.Run("client authentication 'none' should be ignored", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
ClientAuthentication: "original-auth",
ClientAuthenticationOverride: false,
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{
"client_authentication": "none",
},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
assert.Equal(t, "original-auth", result.UserIdentityTokenEndpoint.ClientAuthentication)
})
t.Run("non-string values should be ignored", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "original-token-url",
ClientId: "original-client-id",
TokenUrlOverride: false,
ClientIdOverride: false,
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{
"token_url": 12345,
"client_id": []string{"array", "value"},
},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
assert.Equal(t, "original-token-url", result.UserIdentityTokenEndpoint.TokenUrl)
assert.Equal(t, "original-client-id", result.UserIdentityTokenEndpoint.ClientId)
})
t.Run("Nil UserIdentityTokenEndpoint should not panic", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: nil,
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{
"token_url": "sso-token-url",
},
}
require.NotPanics(t, func() {
mergeAzureSettings(currSettings, azureAdSettings)
})
})
t.Run("Empty SSO settings map", func(t *testing.T) {
currSettings := &azsettings.AzureSettings{
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "original-token-url",
ClientAuthentication: "original-auth",
ClientId: "original-client-id",
},
}
azureAdSettings := &pluginsso.Settings{
Values: map[string]any{},
}
result := mergeAzureSettings(currSettings, azureAdSettings)
assert.Equal(t, "original-token-url", result.UserIdentityTokenEndpoint.TokenUrl)
assert.Equal(t, "original-auth", result.UserIdentityTokenEndpoint.ClientAuthentication)
assert.Equal(t, "original-client-id", result.UserIdentityTokenEndpoint.ClientId)
})
}
@@ -13,23 +13,27 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/login/social"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/envvars"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
)
var _ envvars.Provider = (*EnvVarsProvider)(nil)
type EnvVarsProvider struct {
cfg *PluginInstanceCfg
license plugins.Licensing
logger log.Logger
cfg *PluginInstanceCfg
license plugins.Licensing
logger log.Logger
ssoSettings pluginsso.SettingsProvider
}
func NewEnvVarsProvider(cfg *PluginInstanceCfg, license plugins.Licensing) *EnvVarsProvider {
func NewEnvVarsProvider(cfg *PluginInstanceCfg, license plugins.Licensing, ssoSettings pluginsso.SettingsProvider) *EnvVarsProvider {
return &EnvVarsProvider{
cfg: cfg,
license: license,
logger: log.New("plugins.envvars"),
cfg: cfg,
license: license,
logger: log.New("plugins.envvars"),
ssoSettings: ssoSettings,
}
}
@@ -63,7 +67,7 @@ func (p *EnvVarsProvider) PluginEnvVars(ctx context.Context, plugin *plugins.Plu
hostEnv = append(hostEnv, p.featureToggleEnableVars(ctx)...)
hostEnv = append(hostEnv, p.awsEnvVars(plugin.PluginID())...)
hostEnv = append(hostEnv, p.secureSocksProxyEnvVars()...)
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(p.cfg.Azure)...)
hostEnv = append(hostEnv, azsettings.WriteToEnvStr(p.getAzureSettings())...)
hostEnv = append(hostEnv, p.tracingEnvVars(plugin)...)
hostEnv = append(hostEnv, p.pluginSettingsEnvVars(plugin.PluginID())...)
@@ -189,3 +193,15 @@ func (p *EnvVarsProvider) envVar(key, value string) string {
}
return fmt.Sprintf("%s=%s", key, value)
}
func (p *EnvVarsProvider) getAzureSettings() *azsettings.AzureSettings {
azureSettings := p.cfg.Azure
if azureSettings == nil {
azureSettings = &azsettings.AzureSettings{}
}
azureAdSettings, err := p.ssoSettings.GetForProvider(context.Background(), social.AzureADProviderName)
if err != nil {
p.logger.Error("Failed to get SSO settings", "error", err)
}
return mergeAzureSettings(azureSettings, azureAdSettings)
}
@@ -46,7 +46,7 @@ func TestPluginEnvVarsProvider_PluginEnvVars(t *testing.T) {
Features: featuremgmt.WithFeatures(),
}
provider := NewEnvVarsProvider(cfg, licensing)
provider := NewEnvVarsProvider(cfg, licensing, &fakeSSOSettingsProvider{})
envVars := provider.PluginEnvVars(context.Background(), p)
assert.Len(t, envVars, 6)
assert.Equal(t, "GF_VERSION=", envVars[0])
@@ -77,7 +77,7 @@ func TestPluginEnvVarsProvider_skipHostEnvVars(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{})
envVars := provider.PluginEnvVars(context.Background(), p)
// We want to test that the envvars.Provider does not add any of the host env vars.
@@ -93,7 +93,7 @@ func TestPluginEnvVarsProvider_skipHostEnvVars(t *testing.T) {
cfg := setting.NewCfg()
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{})
t.Run("should populate allowed host env vars", func(t *testing.T) {
// Set all allowed variables
@@ -418,7 +418,7 @@ func TestPluginEnvVarsProvider_tracingEnvironmentVariables(t *testing.T) {
},
} {
t.Run(tc.name, func(t *testing.T) {
p := NewEnvVarsProvider(tc.cfg, nil)
p := NewEnvVarsProvider(tc.cfg, nil, &fakeSSOSettingsProvider{})
envVars := p.PluginEnvVars(context.Background(), tc.plugin)
tc.exp(t, envVars)
})
@@ -473,7 +473,7 @@ func TestPluginEnvVarsProvider_authEnvVars(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{})
envVars := provider.PluginEnvVars(context.Background(), p)
assert.Equal(t, "GF_VERSION=", envVars[0])
assert.Equal(t, "GF_APP_URL=https://myorg.com/", envVars[1])
@@ -521,7 +521,7 @@ func TestPluginEnvVarsProvider_awsEnvVars(t *testing.T) {
Features: featuremgmt.WithFeatures(),
}
provider := NewEnvVarsProvider(cfg, nil)
provider := NewEnvVarsProvider(cfg, nil, &fakeSSOSettingsProvider{})
envVars := provider.PluginEnvVars(context.Background(), p)
assert.ElementsMatch(t, tc.expected, envVars)
}
@@ -540,7 +540,7 @@ func TestPluginEnvVarsProvider_featureToggleEnvVar(t *testing.T) {
Features: featuremgmt.WithFeatures(expectedFeatures[0], true, expectedFeatures[1], true),
}
p := NewEnvVarsProvider(cfg, nil)
p := NewEnvVarsProvider(cfg, nil, &fakeSSOSettingsProvider{})
envVars := p.PluginEnvVars(context.Background(), &plugins.Plugin{})
assert.Equal(t, 2, len(envVars))
@@ -591,7 +591,7 @@ func TestPluginEnvVarsProvider_azureEnvVars(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{})
envVars := provider.PluginEnvVars(context.Background(), &plugins.Plugin{})
assert.ElementsMatch(t, []string{"GF_VERSION=", "GFAZPL_AZURE_CLOUD=AzureCloud", "GFAZPL_AZURE_AUTH_ENABLED=true",
"GFAZPL_MANAGED_IDENTITY_ENABLED=true",
@@ -608,4 +608,113 @@ func TestPluginEnvVarsProvider_azureEnvVars(t *testing.T) {
"GFAZPL_USER_IDENTITY_ASSERTION=username",
}, envVars)
})
t.Run("sets user token endpoint settings from SSO settings for an Azure plugin", func(t *testing.T) {
cfg := &setting.Cfg{
Raw: ini.Empty(),
Azure: &azsettings.AzureSettings{
AzureAuthEnabled: true,
Cloud: azsettings.AzurePublic,
ManagedIdentityEnabled: true,
ManagedIdentityClientId: "mock_managed_identity_client_id",
WorkloadIdentityEnabled: true,
WorkloadIdentitySettings: &azsettings.WorkloadIdentitySettings{
TenantId: "mock_workload_identity_tenant_id",
ClientId: "mock_workload_identity_client_id",
TokenFile: "mock_workload_identity_token_file",
},
UserIdentityEnabled: true,
UserIdentityFallbackCredentialsEnabled: true,
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "mock_user_identity_token_url",
ClientId: "mock_user_identity_client_id",
ClientSecret: "mock_user_identity_client_secret",
UsernameAssertion: true,
},
},
}
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{
GetForProviderFunc: getAzureSSOSettings,
})
envVars := provider.PluginEnvVars(context.Background(), &plugins.Plugin{})
assert.ElementsMatch(t, []string{"GF_VERSION=", "GFAZPL_AZURE_CLOUD=AzureCloud", "GFAZPL_AZURE_AUTH_ENABLED=true",
"GFAZPL_MANAGED_IDENTITY_ENABLED=true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID=mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED=true",
"GFAZPL_WORKLOAD_IDENTITY_TENANT_ID=mock_workload_identity_tenant_id",
"GFAZPL_WORKLOAD_IDENTITY_CLIENT_ID=mock_workload_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_TOKEN_FILE=mock_workload_identity_token_file",
"GFAZPL_USER_IDENTITY_ENABLED=true",
"GFAZPL_USER_IDENTITY_FALLBACK_SERVICE_CREDENTIALS_ENABLED=true",
"GFAZPL_USER_IDENTITY_TOKEN_URL=sso_user_identity_token_url",
"GFAZPL_USER_IDENTITY_CLIENT_AUTHENTICATION=sso_user_client_authentication",
"GFAZPL_USER_IDENTITY_CLIENT_ID=sso_user_identity_client_id",
"GFAZPL_USER_IDENTITY_CLIENT_SECRET=sso_user_identity_client_secret",
"GFAZPL_USER_IDENTITY_MANAGED_IDENTITY_CLIENT_ID=sso_user_identity_managed_identity_client_id",
"GFAZPL_USER_IDENTITY_FEDERATED_CREDENTIAL_AUDIENCE=sso_user_identity_federated_credential_audience",
"GFAZPL_USER_IDENTITY_ASSERTION=username",
}, envVars)
})
t.Run("does not use SSO settings if overrides have been set for an Azure plugin", func(t *testing.T) {
cfg := &setting.Cfg{
Raw: ini.Empty(),
Azure: &azsettings.AzureSettings{
AzureAuthEnabled: true,
Cloud: azsettings.AzurePublic,
ManagedIdentityEnabled: true,
ManagedIdentityClientId: "mock_managed_identity_client_id",
WorkloadIdentityEnabled: true,
WorkloadIdentitySettings: &azsettings.WorkloadIdentitySettings{
TenantId: "mock_workload_identity_tenant_id",
ClientId: "mock_workload_identity_client_id",
TokenFile: "mock_workload_identity_token_file",
},
UserIdentityEnabled: true,
UserIdentityFallbackCredentialsEnabled: true,
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "override_user_identity_token_url",
TokenUrlOverride: true,
ClientAuthentication: "override_user_client_authentication",
ClientAuthenticationOverride: true,
ClientId: "override_user_identity_client_id",
ClientIdOverride: true,
ClientSecret: "override_user_identity_client_secret",
ClientSecretOverride: true,
ManagedIdentityClientId: "override_user_identity_managed_identity_client_id",
ManagedIdentityClientIdOverride: true,
FederatedCredentialAudience: "override_user_identity_federated_credential_audience",
FederatedCredentialAudienceOverride: true,
},
},
}
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
provider := NewEnvVarsProvider(pCfg, nil, &fakeSSOSettingsProvider{
GetForProviderFunc: getAzureSSOSettings,
})
envVars := provider.PluginEnvVars(context.Background(), &plugins.Plugin{})
assert.ElementsMatch(t, []string{"GF_VERSION=", "GFAZPL_AZURE_CLOUD=AzureCloud", "GFAZPL_AZURE_AUTH_ENABLED=true",
"GFAZPL_MANAGED_IDENTITY_ENABLED=true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID=mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED=true",
"GFAZPL_WORKLOAD_IDENTITY_TENANT_ID=mock_workload_identity_tenant_id",
"GFAZPL_WORKLOAD_IDENTITY_CLIENT_ID=mock_workload_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_TOKEN_FILE=mock_workload_identity_token_file",
"GFAZPL_USER_IDENTITY_ENABLED=true",
"GFAZPL_USER_IDENTITY_FALLBACK_SERVICE_CREDENTIALS_ENABLED=true",
"GFAZPL_USER_IDENTITY_TOKEN_URL=override_user_identity_token_url",
"GFAZPL_USER_IDENTITY_CLIENT_AUTHENTICATION=override_user_client_authentication",
"GFAZPL_USER_IDENTITY_CLIENT_ID=override_user_identity_client_id",
"GFAZPL_USER_IDENTITY_CLIENT_SECRET=override_user_identity_client_secret",
"GFAZPL_USER_IDENTITY_MANAGED_IDENTITY_CLIENT_ID=override_user_identity_managed_identity_client_id",
"GFAZPL_USER_IDENTITY_FEDERATED_CREDENTIAL_AUDIENCE=override_user_identity_federated_credential_audience",
}, envVars)
})
}
@@ -9,11 +9,14 @@ import (
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/proxy"
"github.com/grafana/grafana-plugin-sdk-go/experimental/featuretoggles"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/login/social"
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
)
var _ PluginRequestConfigProvider = (*RequestConfigProvider)(nil)
@@ -23,12 +26,16 @@ type PluginRequestConfigProvider interface {
}
type RequestConfigProvider struct {
cfg *PluginInstanceCfg
cfg *PluginInstanceCfg
ssoSettings pluginsso.SettingsProvider
logger log.Logger
}
func NewRequestConfigProvider(cfg *PluginInstanceCfg) *RequestConfigProvider {
func NewRequestConfigProvider(cfg *PluginInstanceCfg, ssoSettings pluginsso.SettingsProvider) *RequestConfigProvider {
return &RequestConfigProvider{
cfg: cfg,
cfg: cfg,
ssoSettings: ssoSettings,
logger: log.New("pluginrequestconfig"),
}
}
@@ -89,8 +96,19 @@ func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginI
if s.cfg.AzureAuthEnabled {
m[azsettings.AzureAuthEnabled] = strconv.FormatBool(s.cfg.AzureAuthEnabled)
}
azureSettings := s.cfg.Azure
if azureSettings != nil && slices.Contains[[]string, string](azureSettings.ForwardSettingsPlugins, pluginID) {
if azureSettings == nil {
azureSettings = &azsettings.AzureSettings{}
}
if slices.Contains(azureSettings.ForwardSettingsPlugins, pluginID) {
azureAdSettings, err := s.ssoSettings.GetForProvider(ctx, social.AzureADProviderName)
if err != nil {
s.logger.Error("Failed to get SSO settings", "error", err)
}
azureSettings = mergeAzureSettings(azureSettings, azureAdSettings)
if azureSettings.Cloud != "" {
m[azsettings.AzureCloud] = azureSettings.Cloud
}
@@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/plugins/auth"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
"github.com/grafana/grafana/pkg/setting"
)
@@ -19,7 +20,7 @@ func TestRequestConfigProvider_PluginRequestConfig_Defaults(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Equal(t, map[string]string{
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0",
"GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0",
@@ -133,7 +134,7 @@ func TestRequestConfigProvider_PluginRequestConfig(t *testing.T) {
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
p := NewRequestConfigProvider(tc.cfg)
p := NewRequestConfigProvider(tc.cfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), tc.expected)
})
}
@@ -168,7 +169,7 @@ func TestRequestConfigProvider_PluginRequestConfig_featureToggles(t *testing.T)
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), tc.features)
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), tc.expectedConfig)
}
})
@@ -182,7 +183,7 @@ func TestRequestConfigProvider_PluginRequestConfig_appURL(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GF_APP_URL": "https://myorg.com/"})
})
}
@@ -198,7 +199,7 @@ func TestRequestConfigProvider_PluginRequestConfig_SQL(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{
"GF_SQL_ROW_LIMIT": "23",
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "24",
@@ -216,7 +217,7 @@ func TestRequestConfigProvider_PluginRequestConfig_SQL(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Equal(t, map[string]string{
"GF_SQL_MAX_OPEN_CONNS_DEFAULT": "0",
"GF_SQL_MAX_IDLE_CONNS_DEFAULT": "0",
@@ -233,7 +234,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GF_CONCURRENT_QUERY_COUNT": "42"})
})
@@ -242,7 +243,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GF_CONCURRENT_QUERY_COUNT")
})
@@ -253,7 +254,7 @@ func TestRequestConfigProvider_PluginRequestConfig_concurrentQueryCount(t *testi
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GF_CONCURRENT_QUERY_COUNT")
})
}
@@ -265,7 +266,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
Features: featuremgmt.WithFeatures(),
}
p := NewRequestConfigProvider(cfg)
p := NewRequestConfigProvider(cfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", nil), map[string]string{"GFAZPL_AZURE_AUTH_ENABLED": "true"})
})
@@ -274,7 +275,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
Features: featuremgmt.WithFeatures(),
}
p := NewRequestConfigProvider(cfg)
p := NewRequestConfigProvider(cfg, &fakeSSOSettingsProvider{})
require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GFAZPL_AZURE_AUTH_ENABLED")
})
@@ -284,7 +285,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azureAuthEnabled(t *testing.T
Features: featuremgmt.WithFeatures(),
}
p := NewRequestConfigProvider(cfg)
p := NewRequestConfigProvider(cfg, &fakeSSOSettingsProvider{})
require.NotContains(t, p.PluginRequestConfig(context.Background(), "", nil), "GFAZPL_AZURE_AUTH_ENABLED")
})
}
@@ -322,7 +323,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
@@ -356,7 +357,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
@@ -384,7 +385,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
m := p.PluginRequestConfig(context.Background(), "", nil)
require.NotContains(t, m, "GFAZPL_AZURE_CLOUD")
require.NotContains(t, m, "GFAZPL_MANAGED_IDENTITY_ENABLED")
@@ -413,7 +414,7 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
@@ -433,6 +434,108 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) {
"GFAZPL_AZURE_ENTRA_PASSWORD_CREDENTIALS_ENABLED": "true",
})
})
t.Run("sets user token endpoint settings from SSO settings for an Azure plugin", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.Azure = azSettings
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{
GetForProviderFunc: getAzureSSOSettings,
})
require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true",
"GFAZPL_WORKLOAD_IDENTITY_TENANT_ID": "mock_workload_identity_tenant_id",
"GFAZPL_WORKLOAD_IDENTITY_CLIENT_ID": "mock_workload_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_TOKEN_FILE": "mock_workload_identity_token_file",
"GFAZPL_USER_IDENTITY_ENABLED": "true",
"GFAZPL_USER_IDENTITY_FALLBACK_SERVICE_CREDENTIALS_ENABLED": "true",
"GFAZPL_USER_IDENTITY_TOKEN_URL": "sso_user_identity_token_url",
"GFAZPL_USER_IDENTITY_CLIENT_AUTHENTICATION": "sso_user_client_authentication",
"GFAZPL_USER_IDENTITY_CLIENT_ID": "sso_user_identity_client_id",
"GFAZPL_USER_IDENTITY_CLIENT_SECRET": "sso_user_identity_client_secret",
"GFAZPL_USER_IDENTITY_MANAGED_IDENTITY_CLIENT_ID": "sso_user_identity_managed_identity_client_id",
"GFAZPL_USER_IDENTITY_FEDERATED_CREDENTIAL_AUDIENCE": "sso_user_identity_federated_credential_audience",
"GFAZPL_USER_IDENTITY_ASSERTION": "username",
"GFAZPL_AZURE_ENTRA_PASSWORD_CREDENTIALS_ENABLED": "true",
})
})
t.Run("does not use SSO settings if overrides have been set for an Azure plugin", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.Azure = &azsettings.AzureSettings{
Cloud: azsettings.AzurePublic,
ManagedIdentityEnabled: true,
ManagedIdentityClientId: "mock_managed_identity_client_id",
WorkloadIdentityEnabled: true,
WorkloadIdentitySettings: &azsettings.WorkloadIdentitySettings{
TenantId: "mock_workload_identity_tenant_id",
ClientId: "mock_workload_identity_client_id",
TokenFile: "mock_workload_identity_token_file",
},
UserIdentityEnabled: true,
UserIdentityTokenEndpoint: &azsettings.TokenEndpointSettings{
TokenUrl: "override_user_identity_token_url",
TokenUrlOverride: true,
ClientAuthentication: "override_user_client_authentication",
ClientAuthenticationOverride: true,
ClientId: "override_user_identity_client_id",
ClientIdOverride: true,
ClientSecret: "override_user_identity_client_secret",
ClientSecretOverride: true,
ManagedIdentityClientId: "override_user_identity_managed_identity_client_id",
ManagedIdentityClientIdOverride: true,
FederatedCredentialAudience: "override_user_identity_federated_credential_audience",
FederatedCredentialAudienceOverride: true,
UsernameAssertion: true,
},
UserIdentityFallbackCredentialsEnabled: true,
ForwardSettingsPlugins: []string{"grafana-azure-monitor-datasource", "prometheus", "grafana-azure-data-explorer-datasource", "mssql", "grafana-azureprometheus-datasource"},
AzureEntraPasswordCredentialsEnabled: true,
}
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{
GetForProviderFunc: getAzureSSOSettings,
})
require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{
"GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true",
"GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true",
"GFAZPL_WORKLOAD_IDENTITY_TENANT_ID": "mock_workload_identity_tenant_id",
"GFAZPL_WORKLOAD_IDENTITY_CLIENT_ID": "mock_workload_identity_client_id",
"GFAZPL_WORKLOAD_IDENTITY_TOKEN_FILE": "mock_workload_identity_token_file",
"GFAZPL_USER_IDENTITY_ENABLED": "true",
"GFAZPL_USER_IDENTITY_FALLBACK_SERVICE_CREDENTIALS_ENABLED": "true",
"GFAZPL_USER_IDENTITY_TOKEN_URL": "override_user_identity_token_url",
"GFAZPL_USER_IDENTITY_CLIENT_AUTHENTICATION": "override_user_client_authentication",
"GFAZPL_USER_IDENTITY_CLIENT_ID": "override_user_identity_client_id",
"GFAZPL_USER_IDENTITY_CLIENT_SECRET": "override_user_identity_client_secret",
"GFAZPL_USER_IDENTITY_MANAGED_IDENTITY_CLIENT_ID": "override_user_identity_managed_identity_client_id",
"GFAZPL_USER_IDENTITY_FEDERATED_CREDENTIAL_AUDIENCE": "override_user_identity_federated_credential_audience",
"GFAZPL_USER_IDENTITY_ASSERTION": "username",
"GFAZPL_AZURE_ENTRA_PASSWORD_CREDENTIALS_ENABLED": "true",
})
})
}
func getAzureSSOSettings(ctx context.Context, provider string) (*pluginsso.Settings, error) {
return &pluginsso.Settings{
Values: map[string]any{
"token_url": "sso_user_identity_token_url",
"client_authentication": "sso_user_client_authentication",
"client_id": "sso_user_identity_client_id",
"client_secret": "sso_user_identity_client_secret",
"managed_identity_client_id": "sso_user_identity_managed_identity_client_id",
"federated_credential_audience": "sso_user_identity_federated_credential_audience",
},
}, nil
}
func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
@@ -447,7 +550,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
cfg.AWSListMetricsPageLimit = "100"
cfg.AWSForwardSettingsPlugins = []string{"cloudwatch", "prometheus", "elasticsearch"}
p := NewRequestConfigProvider(cfg)
p := NewRequestConfigProvider(cfg, &fakeSSOSettingsProvider{})
t.Run("uses the aws settings for an AWS plugin", func(t *testing.T) {
require.Subset(t, p.PluginRequestConfig(context.Background(), "cloudwatch", nil), map[string]string{
@@ -471,7 +574,7 @@ func TestRequestConfigProvider_PluginRequestConfig_aws(t *testing.T) {
t.Run("uses the aws settings for a non-aws user-specified plugin", func(t *testing.T) {
cfg.AWSForwardSettingsPlugins = append(cfg.AWSForwardSettingsPlugins, "test-datasource")
p = NewRequestConfigProvider(cfg)
p = NewRequestConfigProvider(cfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "test-datasource", nil), map[string]string{
"AWS_AUTH_AssumeRoleEnabled": "false",
"AWS_AUTH_AllowedAuthProviders": "grafana_assume_role,keys",
@@ -489,9 +592,20 @@ func TestRequestConfigProvider_PluginRequestConfig_appClientSecret(t *testing.T)
pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures())
require.NoError(t, err)
p := NewRequestConfigProvider(pCfg)
p := NewRequestConfigProvider(pCfg, &fakeSSOSettingsProvider{})
require.Subset(t, p.PluginRequestConfig(context.Background(), "", &auth.ExternalService{
ClientSecret: "mysecret",
}), map[string]string{backend.AppClientSecret: "mysecret"})
})
}
type fakeSSOSettingsProvider struct {
GetForProviderFunc func(ctx context.Context, provider string) (*pluginsso.Settings, error)
}
func (m *fakeSSOSettingsProvider) GetForProvider(ctx context.Context, provider string) (*pluginsso.Settings, error) {
if m.GetForProviderFunc != nil {
return m.GetForProviderFunc(ctx, provider)
}
return nil, nil
}
@@ -54,6 +54,7 @@ import (
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings"
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsso"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/services/pluginsintegration/provisionedplugins"
"github.com/grafana/grafana/pkg/services/pluginsintegration/renderer"
@@ -134,6 +135,8 @@ var WireSet = wire.NewSet(
wire.Bind(new(advisor.AdvisorStats), new(*advisor.Service)),
pluginchecker.ProvideService,
wire.Bind(new(pluginchecker.PluginUpdateChecker), new(*pluginchecker.Service)),
pluginsso.ProvideDefaultSettingsProvider,
wire.Bind(new(pluginsso.SettingsProvider), new(*pluginsso.DefaultSettingsProvider)),
)
// WireExtensionSet provides a wire.ProviderSet of plugin providers that can be
@@ -0,0 +1,41 @@
package pluginsso
import (
"context"
"github.com/grafana/grafana/pkg/services/ssosettings"
)
// SettingsProvider is used to get the SSO settings for a given provider.
type SettingsProvider interface {
GetForProvider(ctx context.Context, provider string) (*Settings, error)
}
type Settings struct {
Values map[string]any
}
// DefaultSettingsProvider is the default implementation of the SettingsProvider interface.
// It uses the SSO settings service to get the settings for a given provider.
type DefaultSettingsProvider struct {
ssoSettings ssosettings.Service
}
func ProvideDefaultSettingsProvider(ssoSettings ssosettings.Service) *DefaultSettingsProvider {
return &DefaultSettingsProvider{
ssoSettings: ssoSettings,
}
}
// GetForProvider returns the SSO settings for a given provider.
// The settings are fetched from the cache if available, otherwise they are fetched from the database.
func (p *DefaultSettingsProvider) GetForProvider(ctx context.Context, provider string) (*Settings, error) {
settings, err := p.ssoSettings.GetForProviderFromCache(ctx, provider)
if err != nil {
return nil, err
}
return &Settings{
Values: settings.Settings,
}, nil
}
+6
View File
@@ -59,22 +59,28 @@ func (cfg *Cfg) readAzureSettings() {
// Override individual settings
if val := azureSection.Key("user_identity_token_url").String(); val != "" {
tokenEndpointSettings.TokenUrl = val
tokenEndpointSettings.TokenUrlOverride = true
}
if val := azureSection.Key("user_identity_client_authentication").String(); val != "" {
tokenEndpointSettings.ClientAuthentication = val
tokenEndpointSettings.ClientAuthenticationOverride = true
}
if val := azureSection.Key("user_identity_client_id").String(); val != "" {
tokenEndpointSettings.ClientId = val
tokenEndpointSettings.ClientIdOverride = true
tokenEndpointSettings.ClientSecret = ""
}
if val := azureSection.Key("user_identity_client_secret").String(); val != "" {
tokenEndpointSettings.ClientSecret = val
tokenEndpointSettings.ClientSecretOverride = true
}
if val := azureSection.Key("user_identity_managed_identity_client_id").String(); val != "" {
tokenEndpointSettings.ManagedIdentityClientId = val
tokenEndpointSettings.ManagedIdentityClientIdOverride = true
}
if val := azureSection.Key("user_identity_federated_credential_audience").String(); val != "" {
tokenEndpointSettings.FederatedCredentialAudience = val
tokenEndpointSettings.FederatedCredentialAudienceOverride = true
}
if val := azureSection.Key("username_assertion").String(); val != "" && val == "username" {
tokenEndpointSettings.UsernameAssertion = true