From 307582d9d193f282fc20182468a02ed0c55b4f99 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Fri, 24 Jan 2020 23:09:50 -0600 Subject: sip authenticator --- Makefile | 4 ++- cmd/vpnweb/vpnweb.go | 2 +- pkg/auth/middleware.go | 30 ++++++++++++++----- pkg/auth/sip2/auth.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ pkg/auth/sip2/client.go | 2 +- pkg/auth/sip2/spec.go | 2 +- pkg/config/main.go | 2 ++ 7 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 pkg/auth/sip2/auth.go diff --git a/Makefile b/Makefile index b000de0..1481a5a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ build: go build cmd/vpnweb/vpnweb.go -demo: +demo-sip: . config/CONFIG && ./vpnweb -notls -auth=sip +demo-anon: + . config/CONFIG && ./vpnweb -notls -auth=anon clean: rm -f public/1/* rm public/ca.crt diff --git a/cmd/vpnweb/vpnweb.go b/cmd/vpnweb/vpnweb.go index ff25e09..f59cc7d 100644 --- a/cmd/vpnweb/vpnweb.go +++ b/cmd/vpnweb/vpnweb.go @@ -25,7 +25,7 @@ func main() { */ http.Handle("/3/cert", auth.RestrictedMiddleware(opts.Auth, ch)) - http.Handle("/3/auth", auth.Authenticator(opts.Auth)) + http.HandleFunc("/3/auth", auth.Authenticator(opts)) /* static files */ diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go index a183c1b..9b42fa9 100644 --- a/pkg/auth/middleware.go +++ b/pkg/auth/middleware.go @@ -1,6 +1,8 @@ package auth import ( + "0xacab.org/leap/vpnweb/pkg/auth/sip2" + "0xacab.org/leap/vpnweb/pkg/config" "0xacab.org/leap/vpnweb/pkg/web" "github.com/auth0/go-jwt-middleware" jwt "github.com/dgrijalva/jwt-go" @@ -12,20 +14,33 @@ const anonAuth string = "anon" const sipAuth string = "sip" /* FIXME -- get this from configuration variables */ -var jwtSecret = []byte("somethingverysecret") -func Authenticator(auth string) { +var jwtSigningSecret = []byte("thesingingkey") + +func bailOnBadAuthModule(module string) { + log.Fatal("Unknown auth module: '", module, "'. Should be one of: ", anonAuth, ", ", sipAuth, ".") +} + +func Authenticator(opts *config.Opts) http.HandlerFunc { + switch opts.Auth { + case anonAuth: + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "no authentication in anon mode", http.StatusBadRequest) + }) + case sipAuth: + return sip2.SipAuthenticator(opts) + default: + bailOnBadAuthModule(opts.Auth) + } + return nil } func RestrictedMiddleware(auth string, ch web.CertHandler) http.Handler { jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { - return jwtSecret, nil + return jwtSigningSecret, nil }, - // When set, the middleware verifies that tokens are signed with the specific signing algorithm - // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks - // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ SigningMethod: jwt.SigningMethodHS256, }) @@ -35,8 +50,7 @@ func RestrictedMiddleware(auth string, ch web.CertHandler) http.Handler { case sipAuth: return jwtMiddleware.Handler(http.HandlerFunc(ch.CertResponder)) default: - log.Fatal("Unknown auth module: '", auth, "'. Should be one of: ", anonAuth, ", ", sipAuth, ".") + bailOnBadAuthModule(auth) } - // should not get here return nil } diff --git a/pkg/auth/sip2/auth.go b/pkg/auth/sip2/auth.go new file mode 100644 index 0000000..1d3f309 --- /dev/null +++ b/pkg/auth/sip2/auth.go @@ -0,0 +1,77 @@ +package sip2 + +import ( + "encoding/json" + jwt "github.com/dgrijalva/jwt-go" + "log" + "net/http" + "time" + + "0xacab.org/leap/vpnweb/pkg/config" +) + +const LibraryLocation string = "testlibrary" +const SipUser string = "leap" +const SipPasswd string = "Kohapassword1!" + +// XXX duplicated, pass in opts +var jwtSigningSecret = []byte("thesingingkey") + +type Credentials struct { + User string + Password string +} + +func SipAuthenticator(opts *config.Opts) http.HandlerFunc { + log.Println("Initializing sip2 authenticator...") + + /* TODO -- should pass specific SIP options as a secondary struct */ + /* TODO -- catch connection errors */ + + sip := NewClient("localhost", "6001", LibraryLocation) + + ok, err := sip.Connect() + if err != nil { + log.Fatal("cannot connect sip client") + } + ok = sip.Login(SipUser, SipPasswd) + if !ok { + log.Println("Error on SIP login") + } else { + log.Println("SIP login ok") + } + + var authTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var c Credentials + + err := json.NewDecoder(r.Body).Decode(&c) + if err != nil { + log.Println("Auth request did not send valid json") + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if c.User == "" || c.Password == "" { + log.Println("Auth request did not include user or password") + http.Error(w, "missing user and/or password", http.StatusBadRequest) + return + } + + valid := sip.CheckCredentials(c.User, c.Password) + if !valid { + log.Println("Wrong auth for user", c.User) + http.Error(w, "wrong user and/or password", http.StatusUnauthorized) + return + } + + log.Println("Valid auth for user", c.User) + token := jwt.New(jwt.SigningMethodHS256) + claims := token.Claims.(jwt.MapClaims) + /* maybe no uid at all */ + claims["uid"] = "user" + claims["exp"] = time.Now().Add(time.Hour * 24).Unix() + tokenString, _ := token.SignedString(jwtSigningSecret) + w.Write([]byte(tokenString)) + }) + return authTokenHandler +} diff --git a/pkg/auth/sip2/client.go b/pkg/auth/sip2/client.go index fbdeded..7116a84 100644 --- a/pkg/auth/sip2/client.go +++ b/pkg/auth/sip2/client.go @@ -27,7 +27,7 @@ func NewClient(host, port, location string) Client { func (c *Client) Connect() (bool, error) { conn, err := telnet.DialTo(c.Host + ":" + c.Port) if nil != err { - log.Println(log.Printf("error: %v", err)) + log.Println("error", err) return false, err } c.conn = conn diff --git a/pkg/auth/sip2/spec.go b/pkg/auth/sip2/spec.go index 9c4ac48..60a14d9 100644 --- a/pkg/auth/sip2/spec.go +++ b/pkg/auth/sip2/spec.go @@ -114,7 +114,7 @@ func getParser() *Parser { txt := msg[:len(msg)-len(terminator)] code, err := strconv.Atoi(txt[:2]) if nil != err { - log.Println("Error parsing integer: %s", txt[:2]) + log.Printf("Error parsing integer: %s\n", txt[:2]) } spec := parser.getMessageSpecByCode(code) txt = txt[2:] diff --git a/pkg/config/main.go b/pkg/config/main.go index 142738d..cfa97ed 100644 --- a/pkg/config/main.go +++ b/pkg/config/main.go @@ -19,6 +19,8 @@ type Opts struct { Auth string } +// TODO -- remove use of reflect + func (o *Opts) fallbackToEnv(field string, envVar string, defaultVal string) { r := reflect.ValueOf(o) f := reflect.Indirect(r).FieldByName(field) -- cgit v1.2.3