mirror of
https://github.com/gitpod-io/gitpod.git
synced 2025-12-08 17:36:30 +00:00
117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
|
|
// Licensed under the GNU Affero General Public License (AGPL).
|
|
// See License.AGPL.txt in the project root for license information.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
connect "github.com/bufbuild/connect-go"
|
|
"github.com/gitpod-io/gitpod/common-go/util"
|
|
"github.com/gitpod-io/gitpod/components/public-api/go/client"
|
|
v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"
|
|
"github.com/gitpod-io/gitpod/gitpod-cli/pkg/gitpod"
|
|
supervisor "github.com/gitpod-io/gitpod/supervisor/api"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/xerrors"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
var idpTokenOpts struct {
|
|
Audience []string
|
|
Decode bool
|
|
Scope string
|
|
}
|
|
|
|
var idpTokenCmd = &cobra.Command{
|
|
Use: "token",
|
|
Short: "Requests an ID token for this workspace",
|
|
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
|
cmd.SilenceUsage = true
|
|
|
|
ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
tkn, err := idpToken(ctx, idpTokenOpts.Audience, idpTokenOpts.Scope)
|
|
|
|
token, _, err := jwt.NewParser().ParseUnverified(tkn, jwt.MapClaims{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If the user wants to decode the token, then do so.
|
|
if idpTokenOpts.Decode {
|
|
|
|
output := map[string]interface{}{
|
|
"Header": token.Header,
|
|
"Payload": token.Claims,
|
|
}
|
|
|
|
// The header and payload are then marshalled into a map and printed to the screen.
|
|
outputPretty, err := json.MarshalIndent(output, "", " ")
|
|
if err != nil {
|
|
return xerrors.Errorf("Failed to marshal output: %w", err)
|
|
}
|
|
|
|
fmt.Printf("%s\n", outputPretty)
|
|
return nil
|
|
}
|
|
fmt.Println(tkn)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func idpToken(ctx context.Context, audience []string, scope string) (idToken string, err error) {
|
|
wsInfo, err := gitpod.GetWSInfo(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
supervisorConn, err := grpc.Dial(util.GetSupervisorAddress(), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
if err != nil {
|
|
return "", xerrors.Errorf("failed connecting to supervisor: %w", err)
|
|
}
|
|
defer supervisorConn.Close()
|
|
clientToken, err := supervisor.NewTokenServiceClient(supervisorConn).GetToken(ctx, &supervisor.GetTokenRequest{
|
|
Host: wsInfo.GitpodApi.Host,
|
|
Kind: "gitpod",
|
|
Scope: []string{
|
|
"function:getWorkspace",
|
|
},
|
|
})
|
|
if err != nil {
|
|
return "", xerrors.Errorf("failed getting token from supervisor: %w", err)
|
|
}
|
|
|
|
c, err := client.New(client.WithCredentials(clientToken.Token), client.WithURL("https://api."+wsInfo.GitpodApi.Host))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
tkn, err := c.IdentityProvider.GetIDToken(ctx, &connect.Request[v1.GetIDTokenRequest]{
|
|
Msg: &v1.GetIDTokenRequest{
|
|
Audience: audience,
|
|
WorkspaceId: wsInfo.WorkspaceId,
|
|
Scope: scope,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return tkn.Msg.Token, nil
|
|
}
|
|
|
|
func init() {
|
|
idpCmd.AddCommand(idpTokenCmd)
|
|
|
|
idpTokenCmd.Flags().StringArrayVar(&idpTokenOpts.Audience, "audience", nil, "audience of the ID token")
|
|
_ = idpTokenCmd.MarkFlagRequired("audience")
|
|
|
|
idpTokenCmd.Flags().BoolVar(&idpTokenOpts.Decode, "decode", false, "decode token to JSON")
|
|
idpTokenCmd.Flags().StringVar(&idpTokenOpts.Scope, "scope", "", "scopes string of the ID token")
|
|
}
|