Files
zeekay 285bb5a76b rename: ziti → zt across all paths
- Repo names: ziti-* → zt-*
- Go modules: github.com/hanzozt/ziti → github.com/hanzozt/zt
- Docker images: hanzozt/ziti-* → hanzozt/zt-*
- C/Java/JS symbols: ziti_* → zt_*
- File and directory names updated
2026-02-18 18:34:10 -08:00

143 lines
3.7 KiB
Go

package main
import (
"bytes"
"flag"
"fmt"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/hanzozt/edge-api/rest_model"
"github.com/hanzozt/edge-api/rest_util"
nfx509 "github.com/hanzozt/foundation/v2/x509"
"github.com/hanzozt/sdk-golang/zt"
"gopkg.in/square/go-jose.v2/json"
)
func die[T interface{}](res T, err error) T {
if err != nil {
log.Fatal(err)
}
return res
}
func main() {
cfg := flag.String("config", "", "path to config file")
hanzoztURL := flag.String("zt", "https://localhost:1280", "URL of the Hanzo ZT service")
flag.Parse()
var config *zt.Config
if cfg == nil || *cfg == "" {
config = &zt.Config{
ZtAPI: *hanzoztURL,
}
// warning: this call is insecure and should not be used in production
ca := die(rest_util.GetControllerWellKnownCas(*hanzoztURL))
var buf bytes.Buffer
_ = nfx509.MarshalToPem(ca, &buf)
config.ID.CA = buf.String()
} else {
if hanzoztURL == nil || *hanzoztURL == "" {
log.Fatal("Hanzo ZT URL must be specified")
}
config = die(zt.NewConfigFromFile(*cfg))
}
ztx := die(zt.NewContext(config))
err := ztx.Authenticate()
var provider *rest_model.ClientExternalJWTSignerDetail
if err != nil {
fmt.Println("Try authenticating with external provider")
idps := die(ztx.GetExternalSigners())
for idx, idp := range idps {
fmt.Printf("%d: %s\n", idx, *idp.Name)
}
fmt.Printf("Select provider allowing device code flow.\nEnter number[0-%d] to authenticate: ", len(idps)-1)
var id int
_ = die(fmt.Scanf("%d", &id))
provider = idps[id]
}
if provider == nil {
log.Fatal("No provider found")
}
fmt.Printf("Using %s\n", *provider.Name)
resp := die(http.Get(*provider.ExternalAuthURL + "/.well-known/openid-configuration"))
var oidcConfig map[string]interface{}
_ = json.NewDecoder(resp.Body).Decode(&oidcConfig)
deviceAuth := oidcConfig["device_authorization_endpoint"].(string)
scopes := append(provider.Scopes, "openid")
ss := strings.Join(scopes, " ")
resp = die(http.PostForm(deviceAuth, url.Values{
"client_id": {*provider.ClientID},
"scope": {ss},
"audience": {*provider.Audience},
}))
var deviceCode map[string]interface{}
_ = json.NewDecoder(resp.Body).Decode(&deviceCode)
if completeUrl, ok := deviceCode["verification_uri_complete"]; ok {
fmt.Printf("Open %s in your browser\n", completeUrl.(string))
} else if verifyUrl, ok := deviceCode["verification_uri"]; ok {
fmt.Printf("Open %s in your browser, and use code %s\n",
verifyUrl.(string), deviceCode["user_code"].(string))
} else {
log.Fatal("Unable to determine verification URL")
}
interval := time.Duration(int(deviceCode["interval"].(float64))) * time.Second
var token map[string]interface{}
for {
clear(token)
time.Sleep(interval)
tokenUrl := oidcConfig["token_endpoint"].(string)
resp = die(http.PostForm(tokenUrl, url.Values{
"client_id": {*provider.ClientID},
"device_code": {deviceCode["device_code"].(string)},
"grant_type": {"urn:ietf:params:oauth:grant-type:device_code"},
}))
json.NewDecoder(resp.Body).Decode(&token)
errmsg, hasErr := token["error"]
if !hasErr {
break
}
errormsg := errmsg.(string)
if errormsg == "authorization_pending" {
fmt.Println("Waiting for user to authorize...")
continue
}
log.Fatal(errormsg)
}
accessToken := token["access_token"].(string)
tok, _ := jwt.Parse(accessToken, nil)
if claims, ok := tok.Claims.(jwt.MapClaims); ok {
for k, v := range claims {
fmt.Printf("\t%s: %v\n", k, v)
}
}
ztx.LoginWithJWT(accessToken)
err = ztx.Authenticate()
if err != nil {
log.Fatal(err)
}
fmt.Println("Authenticated")
services, _ := ztx.GetServices()
fmt.Println("Available Services:")
for _, svc := range services {
fmt.Printf("\t%s\n", *svc.Name)
}
}