137 lines
2.8 KiB
Go
137 lines
2.8 KiB
Go
package superset
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
|
|
"fiskerinc.com/modules/httpclient"
|
|
"fiskerinc.com/modules/redis"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var errUnauthorized = errors.New("superset unauthorized")
|
|
|
|
type (
|
|
guestTokenRequest struct {
|
|
User user `json:"user"`
|
|
Resources []resource `json:"resources"`
|
|
Rls []rule `json:"rls"`
|
|
}
|
|
user struct {
|
|
UserName string `json:"username"`
|
|
FirstName string `json:"first_name"`
|
|
LastName string `json:"last_name"`
|
|
}
|
|
resource struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
}
|
|
rule struct {
|
|
Clause string `json:"clause"`
|
|
}
|
|
|
|
guestTokenResponse struct {
|
|
Token string `json:"token"`
|
|
}
|
|
)
|
|
|
|
func GetGuestToken(r redis.Client, accToken string) (string, error) {
|
|
token, err := getGuestToken(accToken)
|
|
if err == nil {
|
|
return token, nil
|
|
}
|
|
if err != nil && !errors.Is(err, errUnauthorized) {
|
|
return "", err
|
|
}
|
|
|
|
// if unauthorized
|
|
accToken, err = loginFunc(r)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return getGuestToken(accToken)
|
|
}
|
|
|
|
func getGuestToken(accToken string) (string, error) {
|
|
req, err := getGuestTokenReq(accToken)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
resp, err := httpclient.Client.Do(req)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode == http.StatusUnauthorized {
|
|
return "", errors.WithStack(errUnauthorized)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", errors.Errorf("superset guest token answered with status: %s", resp.Status)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
|
|
var structResp guestTokenResponse
|
|
err = json.Unmarshal(body, &structResp)
|
|
if err != nil {
|
|
return "", errors.WithStack(err)
|
|
}
|
|
|
|
return structResp.Token, nil
|
|
}
|
|
|
|
func getGuestTokenReq(accToken string) (*http.Request, error) {
|
|
body, err := json.Marshal(guestTokenRequest{
|
|
User: user{
|
|
UserName: guestUserName,
|
|
FirstName: guestFirstName,
|
|
LastName: guestLastName,
|
|
},
|
|
Resources: compileResources(accToken),
|
|
Rls: []rule{},
|
|
})
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodPost, host+"/security/guest_token", bytes.NewReader(body))
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
req.Header.Add("Authorization", "Bearer "+accToken)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
return req, nil
|
|
}
|
|
|
|
func compileResources(accToken string) []resource {
|
|
var res []resource
|
|
|
|
dashes, err := GetEmbeddableDashboards(accToken)
|
|
dashIDs := make([]string, 0)
|
|
if err == nil {
|
|
for _, d := range dashes {
|
|
dashIDs = append(dashIDs, d.EmbeddingId)
|
|
}
|
|
}
|
|
|
|
for _, id := range dashIDs {
|
|
if id == "" {
|
|
continue
|
|
}
|
|
res = append(res, resource{
|
|
ID: id,
|
|
Type: "dashboard",
|
|
})
|
|
}
|
|
|
|
return res
|
|
}
|