From 819adbbb708076bcf9d3ee6443c704303aad5a80 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Thu, 30 Jan 2020 19:08:14 -0600 Subject: refactor auth middleware --- pkg/auth/anon/auth.go | 44 +++++++++++++++++ pkg/auth/creds/creds.go | 21 +++++++++ pkg/auth/interfaces.go | 26 ++++++++++ pkg/auth/mechanism.go | 49 +++++++++++++++++++ pkg/auth/mechanism_test.go | 47 ++++++++++++++++++ pkg/auth/middleware.go | 65 ------------------------- pkg/auth/sip2/auth.go | 115 +++++++++++++++++++++------------------------ pkg/auth/sip2/client.go | 69 +++++++++++++++++++-------- pkg/auth/sip2/spec.go | 15 ++++++ pkg/auth/sip2/telnet.go | 15 ++++++ pkg/config/main.go | 15 ++++++ pkg/web/certs.go | 15 ++++++ pkg/web/handlers.go | 15 ++++++ pkg/web/middleware.go | 89 +++++++++++++++++++++++++++++++++++ 14 files changed, 455 insertions(+), 145 deletions(-) create mode 100644 pkg/auth/anon/auth.go create mode 100644 pkg/auth/creds/creds.go create mode 100644 pkg/auth/interfaces.go create mode 100644 pkg/auth/mechanism.go create mode 100644 pkg/auth/mechanism_test.go delete mode 100644 pkg/auth/middleware.go create mode 100644 pkg/web/middleware.go (limited to 'pkg') diff --git a/pkg/auth/anon/auth.go b/pkg/auth/anon/auth.go new file mode 100644 index 0000000..52d2827 --- /dev/null +++ b/pkg/auth/anon/auth.go @@ -0,0 +1,44 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package anon + +import ( + "0xacab.org/leap/vpnweb/pkg/auth/creds" + "0xacab.org/leap/vpnweb/pkg/config" +) + +const Label string = "anon" + +// AnonAuthenticator will allow anyone to get access to a protected resource (Like VPN certificates). +// Used by RiseupVPN +type Authenticator struct { +} + +func (a *Authenticator) GetLabel() string { + return Label +} + +func (a *Authenticator) CheckCredentials(cred *creds.Credentials) bool { + return true +} + +func (a *Authenticator) NeedsCredentials() bool { + return false +} + +func GetAuthenticator(opts *config.Opts, skipInit bool) *Authenticator { + return &Authenticator{} +} diff --git a/pkg/auth/creds/creds.go b/pkg/auth/creds/creds.go new file mode 100644 index 0000000..65b3017 --- /dev/null +++ b/pkg/auth/creds/creds.go @@ -0,0 +1,21 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package creds + +type Credentials struct { + User string + Password string +} diff --git a/pkg/auth/interfaces.go b/pkg/auth/interfaces.go new file mode 100644 index 0000000..619eff8 --- /dev/null +++ b/pkg/auth/interfaces.go @@ -0,0 +1,26 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package auth + +import ( + "0xacab.org/leap/vpnweb/pkg/auth/creds" +) + +type Authenticator interface { + GetLabel() string + NeedsCredentials() bool + CheckCredentials(*creds.Credentials) bool +} diff --git a/pkg/auth/mechanism.go b/pkg/auth/mechanism.go new file mode 100644 index 0000000..8a28739 --- /dev/null +++ b/pkg/auth/mechanism.go @@ -0,0 +1,49 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package auth + +import ( + "0xacab.org/leap/vpnweb/pkg/auth/anon" + "0xacab.org/leap/vpnweb/pkg/auth/sip2" + "0xacab.org/leap/vpnweb/pkg/config" + "log" +) + +func GetAuthenticator(opts *config.Opts, skipConnect bool) Authenticator { + switch opts.Auth { + case anon.Label: + return anon.GetAuthenticator(opts, skipConnect) + case sip2.Label: + doAuthenticationChecks(opts) + return sip2.GetAuthenticator(opts, skipConnect) + default: + bailOnBadAuthModule(opts.Auth) + } + return nil +} + +func doAuthenticationChecks(opts *config.Opts) { + if opts.AuthSecret == "" { + log.Fatal("Need to provide an AuthSecret value for SIP Authentication") + } + if len(opts.AuthSecret) < 20 { + log.Fatal("Please provider an AuthSecret longer than 20 chars") + } +} + +func bailOnBadAuthModule(module string) { + log.Fatal("Unknown auth module: '", module, "'. Should be one of: ", sip2.Label, ", ", anon.Label, ".") +} diff --git a/pkg/auth/mechanism_test.go b/pkg/auth/mechanism_test.go new file mode 100644 index 0000000..1a397b1 --- /dev/null +++ b/pkg/auth/mechanism_test.go @@ -0,0 +1,47 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package auth + +import ( + "0xacab.org/leap/vpnweb/pkg/config" + "os" + "testing" +) + +func TestGetAuthenticator(t *testing.T) { + opts := &config.Opts{} + opts.Auth = "anon" + + a := GetAuthenticator(opts, true) + if a.GetLabel() != "anon" { + t.Errorf("expected anon authenticator") + } + + /* TODO test no secret */ + /* TODO test short secret */ + /* TODO refactor init to return proper errors */ + /* TODO test invalid auth method */ + + os.Setenv("VPNWEB_SIP_USER", "user") + os.Setenv("VPNWEB_SIP_PASS", "pass") + os.Setenv("VPNWEB_SIP_LIBR_LOCATION", "test") + opts.Auth = "sip2" + opts.AuthSecret = "sikret000000000000000000000" + a = GetAuthenticator(opts, true) + if a.GetLabel() != "sip2" { + t.Errorf("expected sip authenticator") + } +} diff --git a/pkg/auth/middleware.go b/pkg/auth/middleware.go deleted file mode 100644 index 280ceeb..0000000 --- a/pkg/auth/middleware.go +++ /dev/null @@ -1,65 +0,0 @@ -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" - "github.com/dgrijalva/jwt-go" - "log" - "net/http" -) - -const ( - anonAuth = "anon" - sip2Auth = "sip" -) - -func bailOnBadAuthModule(module string) { - log.Fatal("Unknown auth module: '", module, "'. Should be one of: ", anonAuth, ", ", sip2Auth, ".") -} - -func checkForAuthSecret(opts *config.Opts) { - if opts.AuthSecret == "" { - log.Fatal("Need to provide a AuthSecret value for SIP Authentication") - } - if len(opts.AuthSecret) < 20 { - log.Fatal("Please provider an AuthSecret longer than 20 chars") - } -} - -func AuthenticatorMiddleware(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 sip2Auth: - checkForAuthSecret(opts) - return sip2.SipAuthenticator(opts) - default: - bailOnBadAuthModule(opts.Auth) - } - return nil -} - -func RestrictedMiddleware(opts *config.Opts, ch web.CertHandler) http.Handler { - - jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ - ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { - return []byte(opts.AuthSecret), nil - }, - SigningMethod: jwt.SigningMethodHS256, - }) - - switch opts.Auth { - case anonAuth: - return http.HandlerFunc(ch.CertResponder) - case sip2Auth: - checkForAuthSecret(opts) - return jwtMiddleware.Handler(http.HandlerFunc(ch.CertResponder)) - default: - bailOnBadAuthModule(opts.Auth) - } - return nil -} diff --git a/pkg/auth/sip2/auth.go b/pkg/auth/sip2/auth.go index 9c01c28..47733c2 100644 --- a/pkg/auth/sip2/auth.go +++ b/pkg/auth/sip2/auth.go @@ -1,33 +1,46 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package sip2 import ( - "encoding/json" - "github.com/dgrijalva/jwt-go" + "errors" "log" - "net/http" "os" - "time" "0xacab.org/leap/vpnweb/pkg/config" ) -const sipUserVar string = "VPNWEB_SIP_USER" -const sipPassVar string = "VPNWEB_SIP_PASS" -const sipPortVar string = "VPNWEB_SIP_PORT" -const sipHostVar string = "VPNWEB_SIP_HOST" -const sipLibrLocVar string = "VPNWEB_SIP_LIBR_LOCATION" -const sipTerminatorVar string = "VPNWEB_SIP_TERMINATOR" -const sipDefaultTerminator string = "\r\n" - -type Credentials struct { - User string - Password string -} +const ( + sipUserVar string = "VPNWEB_SIP_USER" + sipPassVar string = "VPNWEB_SIP_PASS" + sipPortVar string = "VPNWEB_SIP_PORT" + sipHostVar string = "VPNWEB_SIP_HOST" + sipLibrLocVar string = "VPNWEB_SIP_LIBR_LOCATION" + sipTerminatorVar string = "VPNWEB_SIP_TERMINATOR" + sipDefaultTerminator string = "\r\n" +) -func getConfigFromEnv(envVar string) string { +func getConfigFromEnv(envVar, defaultVar string) string { val, exists := os.LookupEnv(envVar) if !exists { - log.Fatal("Need to set required env var:", envVar) + if defaultVar == "" { + log.Fatal("Need to set required env var: ", envVar) + } else { + return defaultVar + } } return val } @@ -41,60 +54,40 @@ func setupTerminatorFromEnv() { } } -func SipAuthenticator(opts *config.Opts) http.HandlerFunc { - +func initializeSipConnection(skipConnect bool) (sipClient, error) { log.Println("Initializing SIP2 authenticator") - SipUser := getConfigFromEnv(sipUserVar) - SipPass := getConfigFromEnv(sipPassVar) - SipHost := getConfigFromEnv(sipHostVar) - SipPort := getConfigFromEnv(sipPortVar) - SipLibrLoc := getConfigFromEnv(sipLibrLocVar) + user := getConfigFromEnv(sipUserVar, "") + pass := getConfigFromEnv(sipPassVar, "") + host := getConfigFromEnv(sipHostVar, "localhost") + port := getConfigFromEnv(sipPortVar, "6001") + loc := getConfigFromEnv(sipLibrLocVar, "") setupTerminatorFromEnv() - sip := NewClient(SipHost, SipPort, SipLibrLoc) + sip := newClient(host, port, loc) + + if skipConnect { + // mainly for testing purposes at the moment + return sip, nil + } ok, err := sip.Connect() if err != nil { - log.Fatal("Cannot connect sip client") + return sip, err } - ok = sip.Login(SipUser, SipPass) + ok = sip.Login(user, pass) if !ok { - log.Fatal("Error on SIP login") - } else { - log.Println("SIP login ok") + return sip, errors.New("SIP login error") } + return sip, nil +} - 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 - } +func GetAuthenticator(opts *config.Opts, skipConnect bool) *sipClient { - log.Println("Valid auth for user", c.User) - token := jwt.New(jwt.SigningMethodHS256) - claims := token.Claims.(jwt.MapClaims) - claims["exp"] = time.Now().Add(time.Hour * 24).Unix() - tokenString, _ := token.SignedString([]byte(opts.AuthSecret)) - w.Write([]byte(tokenString)) - }) - return authTokenHandler + sip, err := initializeSipConnection(skipConnect) + if err != nil { + log.Fatal("Cannot initialize sip:", err) + } + return &sip } diff --git a/pkg/auth/sip2/client.go b/pkg/auth/sip2/client.go index 7116a84..9adf218 100644 --- a/pkg/auth/sip2/client.go +++ b/pkg/auth/sip2/client.go @@ -1,31 +1,50 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package sip2 import ( + "0xacab.org/leap/vpnweb/pkg/auth/creds" "fmt" "github.com/reiver/go-telnet" "log" "time" ) -const loginRequestTemplate string = "9300CN%s|CO%s|CP%s|" -const statusRequestTemplate string = "23000%s %sAO%s|AA%s|AD%s|" +const ( + Label string = "sip2" + loginRequestTemplate string = "9300CN%s|CO%s|CP%s|" + statusRequestTemplate string = "23000%s %sAO%s|AA%s|AD%s|" +) -type Client struct { - Host string - Port string +type sipClient struct { + host string + port string location string conn *telnet.Conn parser *Parser } -func NewClient(host, port, location string) Client { - c := Client{host, port, location, nil, nil} +func newClient(host, port, location string) sipClient { + c := sipClient{host, port, location, nil, nil} c.parser = getParser() return c } -func (c *Client) Connect() (bool, error) { - conn, err := telnet.DialTo(c.Host + ":" + c.Port) +func (c *sipClient) Connect() (bool, error) { + conn, err := telnet.DialTo(c.host + ":" + c.port) if nil != err { log.Println("error", err) return false, err @@ -34,7 +53,7 @@ func (c *Client) Connect() (bool, error) { return true, nil } -func (c *Client) Login(user, pass string) bool { +func (c *sipClient) Login(user, pass string) bool { loginStr := fmt.Sprintf(loginRequestTemplate, user, pass, c.location) if nil == c.conn { fmt.Println("error! null connection") @@ -42,14 +61,31 @@ func (c *Client) Login(user, pass string) bool { telnetSend(c.conn, loginStr) loginResp := telnetRead(c.conn) msg := c.parseResponse(loginResp) - if value, ok := c.parser.getFixedFieldValue(msg, Ok); ok && value == TRUE { + if value, ok := c.parser.getFixedFieldValue(msg, okVal); ok && value == trueVal { return true } return false } -func (c *Client) CheckCredentials(user, passwd string) bool { +func (c *sipClient) parseResponse(txt string) *message { + msg := c.parser.parseMessage(txt) + return msg +} + +/* Authenticator interface */ + +func (c *sipClient) GetLabel() string { + return Label +} + +func (c *sipClient) NeedsCredentials() bool { + return true +} + +func (c *sipClient) CheckCredentials(credentials *creds.Credentials) bool { currentTime := time.Now() + user := credentials.User + passwd := credentials.Password statusRequest := fmt.Sprintf( statusRequestTemplate, currentTime.Format("20060102"), @@ -58,8 +94,8 @@ func (c *Client) CheckCredentials(user, passwd string) bool { telnetSend(c.conn, statusRequest) statusMsg := c.parseResponse(telnetRead(c.conn)) - if value, ok := c.parser.getFieldValue(statusMsg, ValidPatron); ok && value == YES { - if value, ok := c.parser.getFieldValue(statusMsg, ValidPatronPassword); ok && value == YES { + if value, ok := c.parser.getFieldValue(statusMsg, validPatron); ok && value == yes { + if value, ok := c.parser.getFieldValue(statusMsg, validPatronPassword); ok && value == yes { return true } } @@ -67,8 +103,3 @@ func (c *Client) CheckCredentials(user, passwd string) bool { // TODO log whatever error we can find (AF, Screen Message, for instance) return false } - -func (c *Client) parseResponse(txt string) *Message { - msg := c.parser.parseMessage(txt) - return msg -} diff --git a/pkg/auth/sip2/spec.go b/pkg/auth/sip2/spec.go index af65b33..09561e6 100644 --- a/pkg/auth/sip2/spec.go +++ b/pkg/auth/sip2/spec.go @@ -1,3 +1,18 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package sip2 import ( diff --git a/pkg/auth/sip2/telnet.go b/pkg/auth/sip2/telnet.go index ae5004e..7d8c4fa 100644 --- a/pkg/auth/sip2/telnet.go +++ b/pkg/auth/sip2/telnet.go @@ -1,3 +1,18 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package sip2 import ( diff --git a/pkg/config/main.go b/pkg/config/main.go index c5b687e..1ce00aa 100644 --- a/pkg/config/main.go +++ b/pkg/config/main.go @@ -1,3 +1,18 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package config import ( diff --git a/pkg/web/certs.go b/pkg/web/certs.go index 9cccc65..779bf72 100644 --- a/pkg/web/certs.go +++ b/pkg/web/certs.go @@ -1,3 +1,18 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package web import ( diff --git a/pkg/web/handlers.go b/pkg/web/handlers.go index b7675f5..633ae95 100644 --- a/pkg/web/handlers.go +++ b/pkg/web/handlers.go @@ -1,3 +1,18 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + package web import ( diff --git a/pkg/web/middleware.go b/pkg/web/middleware.go new file mode 100644 index 0000000..3a74477 --- /dev/null +++ b/pkg/web/middleware.go @@ -0,0 +1,89 @@ +// Copyright (C) 2019 LEAP +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package web + +import ( + "0xacab.org/leap/vpnweb/pkg/auth/creds" + "0xacab.org/leap/vpnweb/pkg/config" + "encoding/json" + "github.com/auth0/go-jwt-middleware" + "github.com/dgrijalva/jwt-go" + "log" + "net/http" + "os" + "strings" + "time" +) + +const debugAuth string = "VPNWEB_DEBUG_AUTH" + +func AuthMiddleware(authenticationFunc func(*creds.Credentials) bool, opts *config.Opts) http.HandlerFunc { + debugAuth, exists := os.LookupEnv(debugAuth) + if !exists { + debugAuth = "false" + } + var authHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var c creds.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 := authenticationFunc(&c) + + if !valid { + log.Println("Wrong auth for user", c.User) + http.Error(w, "Wrong user and/or password", http.StatusUnauthorized) + return + } + + if strings.ToLower(debugAuth) == "yes" { + log.Println("Valid auth for user", c.User) + } + token := jwt.New(jwt.SigningMethodHS256) + claims := token.Claims.(jwt.MapClaims) + claims["expiration"] = time.Now().Add(time.Hour * 24).Unix() + tokenString, _ := token.SignedString([]byte(opts.AuthSecret)) + w.Write([]byte(tokenString)) + }) + return authHandler +} + +func RestrictedMiddleware(shouldProtect func() bool, handler func(w http.ResponseWriter, r *http.Request), opts *config.Opts) http.Handler { + + jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ + ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { + return []byte(opts.AuthSecret), nil + }, + SigningMethod: jwt.SigningMethodHS256, + }) + + switch shouldProtect() { + case false: + return http.HandlerFunc(handler) + case true: + return jwtMiddleware.Handler(http.HandlerFunc(handler)) + } + return nil +} -- cgit v1.2.3