enable auth checking
This commit is contained in:
parent
6736d68446
commit
7303e36a16
|
@ -1,24 +0,0 @@
|
|||
r.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
valid, _ := ctx.Value(MWKey("valid")).(bool)
|
||||
|
||||
if !valid {
|
||||
// misdirection
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
w.Write([]byte("{\"success\":true}\n"))
|
||||
//http.Error(w, `{"error":"could not verify token"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
/*
|
||||
if nil != err2 {
|
||||
// a little misdirection there
|
||||
msg := `{"error":"internal server error"}`
|
||||
http.Error(w, msg, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
})
|
|
@ -1,17 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/mplexer/mgmt/authstore"
|
||||
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
)
|
||||
|
||||
|
@ -44,14 +41,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
b := make([]byte, 16)
|
||||
_, _ = rand.Read(b)
|
||||
claims := &jwt.StandardClaims{
|
||||
Id: base64.RawURLEncoding.EncodeToString(b),
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
|
||||
}
|
||||
tok, err := getToken(secret, claims)
|
||||
tok, err := authstore.HMACToken(secret)
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "signing error: %s", err)
|
||||
os.Exit(1)
|
||||
|
@ -60,25 +50,3 @@ func main() {
|
|||
|
||||
fmt.Println(tok)
|
||||
}
|
||||
|
||||
func getToken(secret string, tokenData *jwt.StandardClaims) (token string, err error) {
|
||||
keyID := authstore.ToPublicKeyString(secret)
|
||||
|
||||
fmt.Fprintf(os.Stderr, "secret: %s\n", secret)
|
||||
fmt.Fprintf(os.Stderr, "kid: %s\n", keyID)
|
||||
|
||||
jwtToken := &jwt.Token{
|
||||
Header: map[string]interface{}{
|
||||
"kid": keyID,
|
||||
"typ": "JWT",
|
||||
"alg": jwt.SigningMethodHS256.Alg(),
|
||||
},
|
||||
Claims: tokenData,
|
||||
Method: jwt.SigningMethodHS256,
|
||||
}
|
||||
|
||||
if token, err = jwtToken.SignedString([]byte(secret)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
|
||||
telebit "git.coolaj86.com/coolaj86/go-telebitd/mplexer"
|
||||
dns01 "git.coolaj86.com/coolaj86/go-telebitd/mplexer/dns01"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/mplexer/mgmt"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/mplexer/mgmt/authstore"
|
||||
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/denisbrodbeck/machineid"
|
||||
|
@ -58,23 +60,16 @@ func main() {
|
|||
enableHTTP01 := flag.Bool("acme-http-01", false, "enable HTTP-01 ACME challenges")
|
||||
enableTLSALPN01 := flag.Bool("acme-tls-alpn-01", false, "enable TLS-ALPN-01 ACME challenges")
|
||||
acmeRelay := flag.String("acme-relay", "", "the base url of the ACME DNS-01 relay, if not the same as the tunnel relay")
|
||||
authURL := flag.String("auth-url", "", "the base url for authentication, if not the same as the tunnel relay")
|
||||
relay := flag.String("relay", "", "the domain (or ip address) at which the relay server is running")
|
||||
secret := flag.String("secret", "", "the same secret used by telebit-relay (used for JWT authentication)")
|
||||
token := flag.String("token", "", "a pre-generated token to give the server (instead of generating one with --secret)")
|
||||
locals := flag.String("locals", "", "a list of <from-domain>:<to-port>")
|
||||
flag.Parse()
|
||||
|
||||
muid, err := machineid.ProtectedID(*appID)
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "unauthorized device")
|
||||
os.Exit(1)
|
||||
}
|
||||
muidb, err := hex.DecodeString(muid)
|
||||
muid = base64.RawURLEncoding.EncodeToString(muidb)
|
||||
|
||||
if len(os.Args) >= 2 {
|
||||
if "version" == os.Args[1] {
|
||||
fmt.Printf("telebit %s %s %s %s", GitVersion, GitRev[:7], GitTimestamp, muid[:24])
|
||||
fmt.Printf("telebit %s %s %s %s", GitVersion, GitRev[:7], GitTimestamp)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +109,19 @@ func main() {
|
|||
domains = append(domains, domain)
|
||||
}
|
||||
|
||||
ppid, err := machineid.ProtectedID(fmt.Sprintf("%s|%s", *appID, *secret))
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "unauthorized device")
|
||||
os.Exit(1)
|
||||
}
|
||||
ppidBytes, err := hex.DecodeString(ppid)
|
||||
ppid = base64.RawURLEncoding.EncodeToString(ppidBytes)
|
||||
|
||||
if "" == *token {
|
||||
if "" == *secret {
|
||||
*secret = os.Getenv("SECRET")
|
||||
}
|
||||
*token, err = getToken(*secret, domains)
|
||||
*token, err = authstore.HMACToken(ppid)
|
||||
}
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "neither secret nor token provided")
|
||||
|
@ -137,6 +140,9 @@ func main() {
|
|||
if "" == *acmeRelay {
|
||||
*acmeRelay = strings.Replace(*relay, "ws", "http", 1) // "https://example.com:443"
|
||||
}
|
||||
if "" == *authURL {
|
||||
*authURL = strings.Replace(*relay, "ws", "http", 1) // "https://example.com:443"
|
||||
}
|
||||
|
||||
if "" != os.Getenv("GODADDY_API_KEY") {
|
||||
id := os.Getenv("GODADDY_API_KEY")
|
||||
|
@ -159,6 +165,21 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
grants, err := mgmt.Inspect(*authURL, *token)
|
||||
if nil != err {
|
||||
_, err := mgmt.Register(*authURL, *secret, ppid)
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "failed to register client: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
grants, err = mgmt.Inspect(*authURL, *token)
|
||||
if nil != err {
|
||||
fmt.Fprintf(os.Stderr, "failed to authenticate after registering client: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
fmt.Println("grants", grants)
|
||||
|
||||
acme := &telebit.ACME{
|
||||
Email: *email,
|
||||
StoragePath: *certpath,
|
||||
|
|
|
@ -20,4 +20,4 @@ echo "PPID: $my_ppid KeyID: $my_keyid"
|
|||
|
||||
TOKEN=$(go run cmd/signjwt/*.go $my_ppid)
|
||||
curl -X POST http://localhost:3000/api/ping -H "Authorization: Bearer ${TOKEN}"
|
||||
curl -X POST http://localhost:3000/api/inspect -H "Authorization: Bearer ${TOKEN}"
|
||||
curl http://localhost:3000/api/inspect -H "Authorization: Bearer ${TOKEN}"
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package mgmt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
telebit "git.coolaj86.com/coolaj86/go-telebitd/mplexer"
|
||||
"git.coolaj86.com/coolaj86/go-telebitd/mplexer/mgmt/authstore"
|
||||
)
|
||||
|
||||
type Grants struct {
|
||||
Domains []string `json:"domains"`
|
||||
}
|
||||
|
||||
func Inspect(authURL, token string) (*Grants, error) {
|
||||
msg, err := telebit.Request("GET", authURL+"/inspect", token, nil)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
if nil == msg {
|
||||
return nil, fmt.Errorf("invalid response")
|
||||
}
|
||||
|
||||
grants := &Grants{}
|
||||
err = json.NewDecoder(msg).Decode(grants)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return grants, nil
|
||||
}
|
||||
|
||||
func Register(authURL, secret, ppid string) (kid string, err error) {
|
||||
pub := authstore.ToPublicKeyString(ppid)
|
||||
jsonb := bytes.NewBuffer([]byte(
|
||||
fmt.Sprintf(`{ "machine_ppid": "%s", "public_key": "%s" }`, ppid, pub),
|
||||
))
|
||||
msg, err := telebit.Request("POST", authURL+"/register-device/"+secret, "", jsonb)
|
||||
if nil != err {
|
||||
return "", err
|
||||
}
|
||||
if nil == msg {
|
||||
return "", fmt.Errorf("invalid response")
|
||||
}
|
||||
|
||||
auth := &authstore.Authorization{}
|
||||
err = json.NewDecoder(msg).Decode(auth)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
msgBytes, _ := ioutil.ReadAll(msg)
|
||||
if "" == auth.PublicKey {
|
||||
return "", fmt.Errorf("unexpected server response: no public key: %s", string(msgBytes))
|
||||
}
|
||||
if pub != auth.PublicKey {
|
||||
return "", fmt.Errorf("server disagrees about public key id: %s vs %s", kid, auth.PublicKey)
|
||||
}
|
||||
return auth.PublicKey, nil
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package authstore
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
var ErrExists = errors.New("token already exists")
|
||||
|
@ -42,3 +45,30 @@ func ToPublicKeyString(secret string) string {
|
|||
}
|
||||
return pub
|
||||
}
|
||||
|
||||
func HMACToken(secret string) (token string, err error) {
|
||||
keyID := ToPublicKeyString(secret)
|
||||
|
||||
b := make([]byte, 16)
|
||||
_, _ = rand.Read(b)
|
||||
claims := &jwt.StandardClaims{
|
||||
Id: base64.RawURLEncoding.EncodeToString(b),
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
|
||||
}
|
||||
|
||||
jwtToken := &jwt.Token{
|
||||
Header: map[string]interface{}{
|
||||
"kid": keyID,
|
||||
"typ": "JWT",
|
||||
"alg": jwt.SigningMethodHS256.Alg(),
|
||||
},
|
||||
Claims: claims,
|
||||
Method: jwt.SigningMethodHS256,
|
||||
}
|
||||
|
||||
if token, err = jwtToken.SignedString([]byte(secret)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ func routeAll() chi.Router {
|
|||
handleDNSRoutes(r)
|
||||
handleDeviceRoutes(r)
|
||||
|
||||
r.Post("/inspect", func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Get("/inspect", func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
claims, ok := ctx.Value(MWKey("claims")).(*MgmtClaims)
|
||||
if !ok {
|
|
@ -1,11 +1,14 @@
|
|||
package telebit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
|
@ -254,3 +257,36 @@ func newCertMagic(acme *ACME) (*certmagic.Config, error) {
|
|||
})
|
||||
return magic, nil
|
||||
}
|
||||
|
||||
func Request(method, fullurl, token string, payload io.Reader) (io.Reader, error) {
|
||||
HTTPClient := &http.Client{
|
||||
Timeout: 15 * time.Second,
|
||||
}
|
||||
req, err := http.NewRequest(method, fullurl, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(token) > 0 {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
if nil != payload {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%d: failed to read response body: %w", resp.StatusCode, err)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return nil, fmt.Errorf("%d: request failed: %v", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(body), nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue