add --expires-in to signjwt

This commit is contained in:
AJ ONeal 2020-07-20 12:18:08 -06:00
parent cfe3820fea
commit ce39066bc8
4 changed files with 79 additions and 5 deletions

View File

@ -104,13 +104,22 @@ Copy `examples/mgmt.env` as `.env` in the working directory.
Create a token with the same `SECRET` used with the `mgmt` server,
and add a device by its `subdomain`.
To build `signjwt`:
```bash
go build -mod=vendor -ldflags "-s -w" -o signjwt cmd/signjwt/*.go
```
To generate an `admin` token:
```bash
VERDOR_ID="test-id"
SECRET="xxxxxxxxxxx"
TOKEN=$(go run -mod=vendor cmd/signjwt/*.go \
TOKEN=$(./signjwt \
--expires-in 15m \
--vendor-id $VENDOR_ID \
--secret $SECRET \
--machine-id $SECRET
--machine-ppid $SECRET
)
```
@ -240,3 +249,21 @@ EOF
python3 -m http.server 3000
```
## Glossary
```
--vendor-id $VENDOR_ID an arbitrary id used as part of authentication
--secret $SECRET the secret for creating JWTs
--auth-url $AUTH_URL the full url prefix of the server that will validate tokens
--tunnel-relay-url $TUNNEL_RELAY_URL the full url of the websocket tunnel server
--locals $LOCALS a list of `scheme:domainname:port`
for forwarding incoming `domainname` to local `port`
--port-forwards $PORT_FORWARDS a list of `remote:local` tcp port-forwarding
--verbose $VERBOSE logs everything, including abbreviated data (as hex)
$VERBOSE_BYTES logs full data (as hex)
$VERBOSE_RAW logs full data (as string)
--acme-agree $ACME_AGREE agree to the ACME service agreement
--acme-email $ACME_EMAIL the webmaster email for ACME notices
--acme-relay-url $ACME_RELAY_URL the server that will relay ACME DNS-01 requests
```

View File

@ -8,6 +8,7 @@ import (
"flag"
"fmt"
"os"
"strconv"
"git.coolaj86.com/coolaj86/go-telebitd/mgmt/authstore"
telebit "git.coolaj86.com/coolaj86/go-telebitd/mplexer"
@ -16,6 +17,15 @@ import (
_ "github.com/joho/godotenv/autoload"
)
var durAbbrs = map[byte]bool{
's': true, // second
'm': true, // minute
'h': true, // hour
'd': true, // day
'w': true, // week
// month and year cannot be measured
}
func main() {
var secret, clientSecret, relaySecret string
@ -23,6 +33,7 @@ func main() {
machineID := flag.String("machine-id", "", "spoof the raw machine id")
vendorID := flag.String("vendor-id", "", "a unique identifier for a deploy target environment")
authURL := flag.String("auth-url", "", "the base url for authentication, if not the same as the tunnel relay")
humanExp := flag.String("expires-in", "15m", "set the token to expire <x> units after `iat` (issued at)")
getMachinePPID := flag.Bool("machine-ppid-only", false, "just print the machine ppid, not the token")
flag.StringVar(&secret, "secret", "", "either the remote server or the tunnel relay secret (used for JWT authentication)")
flag.Parse()
@ -31,6 +42,34 @@ func main() {
*authURL = os.Getenv("AUTH_URL")
}
humanExpLen := len(*humanExp)
if 0 == humanExpLen {
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
expNum, _ := strconv.Atoi((*humanExp)[:humanExpLen-1])
expSuffix := (*humanExp)[humanExpLen-1:]
switch expSuffix {
case "w":
expNum *= 7
fallthrough
case "d":
expNum *= 24
fallthrough
case "h":
expNum *= 60
fallthrough
case "m":
expNum *= 60
fallthrough
case "s":
// do nothing
default:
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
if expNum < 5 {
fmt.Fprintf(os.Stderr, "Invalid --expires-in: %q (minimum: 5s)", *humanExp)
}
if 0 == len(*vendorID) {
*vendorID = os.Getenv("VENDOR_ID")
}
@ -99,7 +138,7 @@ func main() {
fmt.Fprintf(os.Stderr, "[debug] ppid = %s\n", ppid)
fmt.Fprintf(os.Stderr, "[debug] pub = %s\n", pub)
tok, err := authstore.HMACToken(ppid)
tok, err := authstore.HMACToken(ppid, expNum)
if nil != err {
fmt.Fprintf(os.Stderr, "signing error: %s\n", err)
os.Exit(1)

View File

@ -14,6 +14,7 @@ AUTH_URL="${AUTH_URL:-"http://localhost:3000/api"}"
echo "RELAY_SECRET: $RELAY_SECRET"
TOKEN=$(go run cmd/signjwt/*.go \
--expires-in 1m \
--vendor-id "$VENDOR_ID" \
--secret "$RELAY_SECRET" \
--machine-ppid "$RELAY_SECRET"

View File

@ -51,12 +51,19 @@ func ToPublicKeyString(secret string) string {
return pub
}
func HMACToken(secret string) (token string, err error) {
func HMACToken(secret string, maybeExp ...int) (token string, err error) {
keyID := ToPublicKeyString(secret)
if dbg.Debug {
fmt.Fprintf(os.Stderr, "[debug] keyID=%s\n", keyID)
}
var exp int64
if 0 == len(maybeExp) || 0 == maybeExp[0] {
exp = time.Now().Add(5 * time.Minute).Unix()
} else {
exp = time.Now().Add(time.Duration(maybeExp[0]) * time.Second).Unix()
}
b := make([]byte, 16)
_, _ = rand.Read(b)
claims := &jwt.StandardClaims{
@ -64,7 +71,7 @@ func HMACToken(secret string) (token string, err error) {
Subject: "", // TODO
Issuer: "", // TODO
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(5 * time.Minute).Unix(),
ExpiresAt: exp,
}
jwtToken := &jwt.Token{