fully roughed in auth models; none, basic (#12)

This commit is contained in:
Michael Quigley 2022-08-16 13:16:44 -04:00
parent c6c1a470d3
commit d87ec1257a
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
2 changed files with 135 additions and 77 deletions

View File

@ -1,17 +1,15 @@
package main
import (
"fmt"
ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
tb "github.com/nsf/termbox-go"
"github.com/openziti-test-kitchen/zrok/http"
"github.com/openziti-test-kitchen/zrok/model"
"github.com/openziti-test-kitchen/zrok/rest_client_zrok"
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/tunnel"
"github.com/openziti-test-kitchen/zrok/rest_model_zrok"
"github.com/openziti-test-kitchen/zrok/zrokdir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"os"
@ -22,22 +20,34 @@ import (
)
func init() {
rootCmd.AddCommand(httpCmd)
rootCmd.AddCommand(newHttpCommand().cmd)
}
var httpCmd = &cobra.Command{
Use: "http <endpoint>",
Short: "Start an http terminator",
Args: cobra.ExactArgs(1),
Run: handleHttp,
type httpCommand struct {
basicAuth []string
cmd *cobra.Command
}
func handleHttp(_ *cobra.Command, args []string) {
if err := ui.Init(); err != nil {
panic(err)
func newHttpCommand() *httpCommand {
cmd := &cobra.Command{
Use: "http <endpoint>",
Short: "Start an HTTP terminator",
Args: cobra.ExactArgs(1),
}
defer ui.Close()
tb.SetInputMode(tb.InputEsc)
command := &httpCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
cmd.Run = command.run
return command
}
func (self *httpCommand) run(_ *cobra.Command, args []string) {
/*
if err := ui.Init(); err != nil {
panic(err)
}
defer ui.Close()
tb.SetInputMode(tb.InputEsc)
*/
idCfg, err := zrokdir.IdentityConfigFile()
if err != nil {
@ -62,6 +72,19 @@ func handleHttp(_ *cobra.Command, args []string) {
req.Body = &rest_model_zrok.TunnelRequest{
ZitiIdentityID: id,
Endpoint: cfg.EndpointAddress,
AuthScheme: string(model.None),
}
if len(self.basicAuth) > 0 {
logrus.Infof("configuring basic auth")
req.Body.AuthScheme = string(model.Basic)
for _, pair := range self.basicAuth {
tokens := strings.Split(pair, ":")
if len(tokens) == 2 {
req.Body.AuthUsers = append(req.Body.AuthUsers, &rest_model_zrok.AuthUser{Username: strings.TrimSpace(tokens[0]), Password: strings.TrimSpace(tokens[1])})
} else {
panic(errors.Errorf("invalid username:password pair '%v'", pair))
}
}
}
resp, err := zrok.Tunnel.Tunnel(req, auth)
if err != nil {
@ -88,64 +111,69 @@ func handleHttp(_ *cobra.Command, args []string) {
}
}()
ui.Clear()
w, h := ui.TerminalDimensions()
/*
ui.Clear()
w, h := ui.TerminalDimensions()
p := widgets.NewParagraph()
p.Border = true
p.Title = " access your zrok service "
p.Text = fmt.Sprintf("%v%v", strings.Repeat(" ", (((w-12)-len(resp.Payload.ProxyEndpoint))/2)-1), resp.Payload.ProxyEndpoint)
p.TextStyle = ui.Style{Fg: ui.ColorWhite}
p.PaddingTop = 1
p.SetRect(5, 5, w-10, 10)
p := widgets.NewParagraph()
p.Border = true
p.Title = " access your zrok service "
p.Text = fmt.Sprintf("%v%v", strings.Repeat(" ", (((w-12)-len(resp.Payload.ProxyEndpoint))/2)-1), resp.Payload.ProxyEndpoint)
p.TextStyle = ui.Style{Fg: ui.ColorWhite}
p.PaddingTop = 1
p.SetRect(5, 5, w-10, 10)
lastRequests := float64(0)
var requestData []float64
spk := widgets.NewSparkline()
spk.Title = " requests "
spk.Data = requestData
spk.LineColor = ui.ColorCyan
lastRequests := float64(0)
var requestData []float64
spk := widgets.NewSparkline()
spk.Title = " requests "
spk.Data = requestData
spk.LineColor = ui.ColorCyan
slg := widgets.NewSparklineGroup(spk)
slg.SetRect(5, 11, w-10, h-5)
slg := widgets.NewSparklineGroup(spk)
slg.SetRect(5, 11, w-10, h-5)
ui.Render(p, slg)
ui.Render(p, slg)
ticker := time.NewTicker(time.Second).C
uiEvents := ui.PollEvents()
for {
select {
case e := <-uiEvents:
switch e.Type {
case ui.ResizeEvent:
ui.Clear()
w, h = ui.TerminalDimensions()
p.SetRect(5, 5, w-10, 10)
slg.SetRect(5, 11, w-10, h-5)
ui.Render(p, slg)
ticker := time.NewTicker(time.Second).C
uiEvents := ui.PollEvents()
for {
select {
case e := <-uiEvents:
switch e.Type {
case ui.ResizeEvent:
ui.Clear()
w, h = ui.TerminalDimensions()
p.SetRect(5, 5, w-10, 10)
slg.SetRect(5, 11, w-10, h-5)
ui.Render(p, slg)
case ui.KeyboardEvent:
switch e.ID {
case "q", "<C-c>":
ui.Close()
cleanupHttp(id, cfg, zrok, auth)
os.Exit(0)
case ui.KeyboardEvent:
switch e.ID {
case "q", "<C-c>":
ui.Close()
cleanupHttp(id, cfg, zrok, auth)
os.Exit(0)
}
}
}
case <-ticker:
currentRequests := float64(httpProxy.Requests())
deltaRequests := currentRequests - lastRequests
requestData = append(requestData, deltaRequests)
lastRequests = currentRequests
requestData = append(requestData, deltaRequests)
for len(requestData) > w-17 {
requestData = requestData[1:]
case <-ticker:
currentRequests := float64(httpProxy.Requests())
deltaRequests := currentRequests - lastRequests
requestData = append(requestData, deltaRequests)
lastRequests = currentRequests
requestData = append(requestData, deltaRequests)
for len(requestData) > w-17 {
requestData = requestData[1:]
}
spk.Title = fmt.Sprintf(" requests (%d) ", int(currentRequests))
spk.Data = requestData
ui.Render(p, slg)
}
spk.Title = fmt.Sprintf(" requests (%d) ", int(currentRequests))
spk.Data = requestData
ui.Render(p, slg)
}
*/
for {
time.Sleep(30 * time.Second)
}
}

View File

@ -2,7 +2,6 @@ package proxy
import (
"context"
"crypto/subtle"
"fmt"
"github.com/openziti-test-kitchen/zrok/model"
"github.com/openziti-test-kitchen/zrok/util"
@ -39,12 +38,7 @@ func Run(cfg *Config) error {
return err
}
proxy.Transport = zTransport
users := &model.BasicAuth{
Users: []*model.AuthUser{
{Username: "hello", Password: "world"},
},
}
return http.ListenAndServe(cfg.Address, basicAuth(util.NewProxyHandler(proxy), users, "zrok", &resolver{}, zCtx))
return http.ListenAndServe(cfg.Address, basicAuth(util.NewProxyHandler(proxy), "zrok", &resolver{}, zCtx))
}
type resolver struct{}
@ -165,38 +159,74 @@ func getRefreshedService(name string, ctx ziti.Context) (*edge.Service, bool) {
return svc, found
}
func basicAuth(handler http.Handler, users *model.BasicAuth, realm string, rslv ProxyServiceResolver, ctx ziti.Context) http.HandlerFunc {
func basicAuth(handler http.Handler, realm string, rslv ProxyServiceResolver, ctx ziti.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
svcName := rslv.Service(r.Host)
if svc, found := getRefreshedService(svcName, ctx); found {
if cfg, found := svc.Configs[model.ZrokProxyConfig]; found {
if scheme, found := cfg["auth_scheme"]; found {
switch scheme {
case model.None:
case string(model.None):
logrus.Infof("auth scheme none '%v'", svcName)
handler.ServeHTTP(w, r)
return
case model.Basic:
case string(model.Basic):
logrus.Infof("auth scheme basic '%v", svcName)
inUser, inPass, ok := r.BasicAuth()
if !ok {
writeUnauthorizedResponse(w, realm)
return
}
authed := false
for _, v := range users.Users {
if subtle.ConstantTimeCompare([]byte(inUser), []byte(v.Username)) == 1 && subtle.ConstantTimeCompare([]byte(inPass), []byte(v.Password)) == 1 {
authed = true
break
if v, found := cfg["basic_auth"]; found {
if basicAuth, ok := v.(map[string]interface{}); ok {
if v, found := basicAuth["users"]; found {
if arr, ok := v.([]interface{}); ok {
for _, v := range arr {
if um, ok := v.(map[string]interface{}); ok {
username := ""
if v, found := um["username"]; found {
if un, ok := v.(string); ok {
username = un
}
}
password := ""
if v, found := um["password"]; found {
if pw, ok := v.(string); ok {
password = pw
}
}
if username == inUser && password == inPass {
authed = true
break
}
}
}
}
}
}
}
if !authed {
writeUnauthorizedResponse(w, realm)
return
}
handler.ServeHTTP(w, r)
default:
logrus.Infof("invalid auth scheme '%v'", scheme)
writeUnauthorizedResponse(w, realm)
return
}
} else {
logrus.Infof("no auth scheme for '%v'", svcName)
}
} else {
logrus.Infof("no proxy config for '%v'", svcName)
}
} else {
logrus.Infof("service '%v' not found", svcName)
}
}
}