From 7ba061682c8c6f0173b7c4b1af110a458205826d Mon Sep 17 00:00:00 2001 From: Steve Date: Thu, 17 Sep 2020 17:36:39 -0400 Subject: [PATCH] add token generation, validation --- go.mod | 1 + go.sum | 1 + main.go | 37 ++++++++++++++++++++++++++++--- templates/error.html | 5 +++++ templates/token.html | 11 +++++++++ token.go | 53 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 templates/error.html create mode 100644 templates/token.html create mode 100644 token.go diff --git a/go.mod b/go.mod index 3b1722d..85985cd 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module guildgate go 1.14 require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/go-ldap/ldap v3.0.3+incompatible github.com/gorilla/securecookie v1.1.1 github.com/spf13/viper v1.7.1 diff --git a/go.sum b/go.sum index 0a70455..30cc274 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= diff --git a/main.go b/main.go index ceb1d92..f52a51a 100644 --- a/main.go +++ b/main.go @@ -43,9 +43,13 @@ func signupPage(res http.ResponseWriter, req *http.Request) { secret := req.FormValue("secret") if Conf.Secret != "" && Conf.Secret != secret { - log.Printf("Bad secret entered\n") - res.Write([]byte("Get a load of this guy, not knowing the secret code")) - return + //Checking it as a token + err := validateToken(secret) + if err != nil { + log.Printf("Bad secret entered: %v\n", err) + res.Write([]byte("Get a load of this guy, not knowing the secret code")) + return + } } //insert into LDAP log.Printf("Attempting to create account for %v", username) @@ -101,6 +105,32 @@ func logoutPage(res http.ResponseWriter, req *http.Request) { http.Redirect(res, req, "/", 302) } +func tokenPage(res http.ResponseWriter, req *http.Request) { + u := getUserName(req) + if u == "" { + http.Redirect(res, req, "/", 302) + } + token, err := generateToken(u) + if err != nil { + log.Printf("Error generating token: %v", err) + tpl.ExecuteTemplate(res, "error", nil) + } + data := struct { + Title string + Username string + ShowLogin bool + ShowLogout bool + Token string + }{ + "Token Generation", + u, + false, + true, + token, + } + tpl.ExecuteTemplate(res, "token", data) +} + func homePage(res http.ResponseWriter, req *http.Request) { u := getUserName(req) uname := "Unregistered" @@ -128,6 +158,7 @@ func main() { http.HandleFunc("/register", signupPage) http.HandleFunc("/login", loginPage) http.HandleFunc("/logout", logoutPage) + http.HandleFunc("/token", tokenPage) http.HandleFunc("/", homePage) log.Printf("Registering templates from %v/\n", Conf.TplPath) tpl = template.Must(template.ParseGlob(Conf.TplPath + "/*.html")) diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..a3be7e4 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,5 @@ +{{ define "error" }} +{{ template "header" .}} +An error occured. Please let the admin know. +{{template "footer" .}} +{{ end }} diff --git a/templates/token.html b/templates/token.html new file mode 100644 index 0000000..7b05cf7 --- /dev/null +++ b/templates/token.html @@ -0,0 +1,11 @@ +{{ define "token" }} +{{ template "header" .}} +

The following token has been generated and can be used to register an account on this website.

+

It is valid for 24 hours.

+ +

To Use: Paste the following string into the "Secret" box during registration

+ +{{template "footer" .}} +{{ end }} diff --git a/token.go b/token.go new file mode 100644 index 0000000..6c0a168 --- /dev/null +++ b/token.go @@ -0,0 +1,53 @@ +package main + +import ( + "errors" + "log" + "time" + + "github.com/dgrijalva/jwt-go" +) + +type tokenClaim struct { + Sponsor string `json:"sponsor_username"` + jwt.StandardClaims +} + +func generateToken(sponsor string) (string, error) { + claim := tokenClaim{ + Sponsor: sponsor, + StandardClaims: jwt.StandardClaims{ + ExpiresAt: time.Now().UTC().Unix() + 86400, + Issuer: "GuildGate", + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) + signedToken, err := token.SignedString([]byte(Conf.Secret)) + if err != nil { + return "", err + } else { + return signedToken, nil + } +} + +func validateToken(tok string) error { + token, err := jwt.ParseWithClaims( + tok, + &tokenClaim{}, + func(token *jwt.Token) (interface{}, error) { + return []byte(Conf.Secret), nil + }, + ) + if err != nil { + return err + } + claims, ok := token.Claims.(*tokenClaim) + if !ok { + return errors.New("Invalid token sponsor passed") + } + if claims.ExpiresAt < time.Now().UTC().Unix() { + return errors.New("Token has expired") + } + log.Printf("Valid token received; sponsored by %v\n", claims.Sponsor) + return nil +}