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 package main
import ( import (
"fmt"
ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
"github.com/go-openapi/runtime" "github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client" 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/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"
"github.com/openziti-test-kitchen/zrok/rest_client_zrok/tunnel" "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/rest_model_zrok"
"github.com/openziti-test-kitchen/zrok/zrokdir" "github.com/openziti-test-kitchen/zrok/zrokdir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os" "os"
@ -22,22 +20,34 @@ import (
) )
func init() { func init() {
rootCmd.AddCommand(httpCmd) rootCmd.AddCommand(newHttpCommand().cmd)
} }
var httpCmd = &cobra.Command{ type httpCommand struct {
basicAuth []string
cmd *cobra.Command
}
func newHttpCommand() *httpCommand {
cmd := &cobra.Command{
Use: "http <endpoint>", Use: "http <endpoint>",
Short: "Start an http terminator", Short: "Start an HTTP terminator",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Run: handleHttp, }
command := &httpCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...")
cmd.Run = command.run
return command
} }
func handleHttp(_ *cobra.Command, args []string) { func (self *httpCommand) run(_ *cobra.Command, args []string) {
/*
if err := ui.Init(); err != nil { if err := ui.Init(); err != nil {
panic(err) panic(err)
} }
defer ui.Close() defer ui.Close()
tb.SetInputMode(tb.InputEsc) tb.SetInputMode(tb.InputEsc)
*/
idCfg, err := zrokdir.IdentityConfigFile() idCfg, err := zrokdir.IdentityConfigFile()
if err != nil { if err != nil {
@ -62,6 +72,19 @@ func handleHttp(_ *cobra.Command, args []string) {
req.Body = &rest_model_zrok.TunnelRequest{ req.Body = &rest_model_zrok.TunnelRequest{
ZitiIdentityID: id, ZitiIdentityID: id,
Endpoint: cfg.EndpointAddress, 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) resp, err := zrok.Tunnel.Tunnel(req, auth)
if err != nil { if err != nil {
@ -88,6 +111,7 @@ func handleHttp(_ *cobra.Command, args []string) {
} }
}() }()
/*
ui.Clear() ui.Clear()
w, h := ui.TerminalDimensions() w, h := ui.TerminalDimensions()
@ -147,6 +171,10 @@ func handleHttp(_ *cobra.Command, args []string) {
ui.Render(p, slg) ui.Render(p, slg)
} }
} }
*/
for {
time.Sleep(30 * time.Second)
}
} }
func cleanupHttp(id string, cfg *http.Config, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) { func cleanupHttp(id string, cfg *http.Config, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {

View File

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