quorate/packages/grafana-rcon/backend/auth.go

66 lines
1.8 KiB
Go
Raw Normal View History

package main
import (
"encoding/json"
"errors"
"net/http"
"net/url"
"strings"
"time"
"github.com/grafana/authlib/authn"
"github.com/grafana/grafana-plugin-sdk-go/config"
)
type authorizer struct {
url string
client *http.Client
verifier authn.Verifier[struct{}]
}
func newAuthorizer(base string) *authorizer {
base = strings.TrimRight(base, "/")
client := &http.Client{Timeout: 10 * time.Second}
keys := authn.NewKeyRetriever(authn.KeyRetrieverConfig{SigningKeysURL: base + "/api/signing-keys/keys"}, authn.WithHTTPClientKeyRetrieverOpt(client))
return &authorizer{
url: base,
client: client,
verifier: authn.NewVerifier[struct{}](authn.VerifierConfig{}, authn.TokenTypeID, keys),
}
}
func (a *authorizer) canSubmit(req *http.Request) (bool, error) {
cfg := config.GrafanaConfigFromContext(req.Context())
token, err := cfg.PluginAppClientSecret()
if err != nil || token == "" {
return false, errors.New("plugin service account is unavailable")
}
claims, err := a.verifier.Verify(req.Context(), req.Header.Get("X-Grafana-Id"))
if err != nil {
return false, err
}
id, ok := strings.CutPrefix(claims.Subject, "user:")
if !ok || id == "" {
return false, nil
}
request, err := http.NewRequestWithContext(req.Context(), "GET", a.url+"/api/users/"+url.PathEscape(id), nil)
if err != nil {
return false, err
}
request.Header.Set("Authorization", "Bearer "+token)
response, err := a.client.Do(request)
if err != nil {
return false, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return false, errors.New("user lookup is unavailable")
}
var profile struct {
Admin bool `json:"isGrafanaAdmin"`
}
if err := json.NewDecoder(response.Body).Decode(&profile); err != nil {
return false, err
}
return profile.Admin, nil
}