From 8a2f43559f44ed8b658bacccd205db6551a7ccb8 Mon Sep 17 00:00:00 2001 From: George Shaw Date: Mon, 6 Nov 2017 11:07:51 -0600 Subject: [PATCH] referencing issue #56 --- pkg/public/public.go | 16 +++--- pkg/webhost/authentication.go | 88 ++++++++++++++++++++++++++++ pkg/webhost/webhost.go | 105 +++------------------------------- 3 files changed, 105 insertions(+), 104 deletions(-) create mode 100644 pkg/webhost/authentication.go diff --git a/pkg/public/public.go b/pkg/public/public.go index 35e6831..685e4e1 100644 --- a/pkg/public/public.go +++ b/pkg/public/public.go @@ -25,10 +25,10 @@ func NewPublicWeb() PublicWeb { // ServeHTTP function routes all requests for the public web server. It is used in the main // function inside of the http.ListenAndServe() function for the public host. -func (pub *PublicWeb) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (pub *PublicWeb) ServeHTTP(res http.ResponseWriter, req *http.Request) { if pub.MaintenanceMode == 1 { - w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte("We are currently in maintenance mode, please check back later.")) + res.WriteHeader(http.StatusServiceUnavailable) + res.Write([]byte("We are currently in maintenance mode, please check back later.")) } path := req.URL.Path[1:] @@ -41,7 +41,7 @@ func (pub *PublicWeb) ServeHTTP(w http.ResponseWriter, req *http.Request) { f, err := os.Open(path) if err != nil { - routing.HttpThrowStatus(http.StatusNotFound, w) + routing.HttpThrowStatus(http.StatusNotFound, res) logging.Console(logging.PUBLIC_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" rendered a 404 error.") return } @@ -49,16 +49,16 @@ func (pub *PublicWeb) ServeHTTP(w http.ResponseWriter, req *http.Request) { contentType, err := routing.GetContentType(path) if err != nil { - routing.HttpThrowStatus(http.StatusUnsupportedMediaType, w) + routing.HttpThrowStatus(http.StatusUnsupportedMediaType, res) logging.Console(logging.PUBLIC_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" content type could not be determined, 404 error.") return } - w.Header().Add("Content-Type", contentType) - _, err = io.Copy(w, f) + res.Header().Add("Content-Type", contentType) + _, err = io.Copy(res, f) if err != nil { - routing.HttpThrowStatus(http.StatusInternalServerError, w) + routing.HttpThrowStatus(http.StatusInternalServerError, res) logging.Console(logging.PUBLIC_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" rendered a 500 error.") return } diff --git a/pkg/webhost/authentication.go b/pkg/webhost/authentication.go new file mode 100644 index 0000000..8af16f3 --- /dev/null +++ b/pkg/webhost/authentication.go @@ -0,0 +1,88 @@ +// Package webhost handles the logic of the webhosting panel +package webhost + +import ( + "net/http" + "strings" + + "github.com/Ennovar/gPanel/pkg/api/user" + "github.com/Ennovar/gPanel/pkg/networking" + jwt "github.com/dgrijalva/jwt-go" +) + +// reqAuth function checks to see if the given path requires authentication. +func reqAuth(path string) bool { + path = strings.ToLower(path) + + dismissibleTypes := []string{".css", ".js"} + for _, t := range dismissibleTypes { + if strings.HasSuffix(path, t) { + return false + } + } + + dismissibleFiles := []string{ + "index.html", + "user_auth", + "user_register", + "user_logout", + } + for _, f := range dismissibleFiles { + if strings.HasSuffix(path, f) { + return false + } + } + + return true +} + +// checkAuth function returns a boolean based on whether or not the current +// caller is authenticated based off of encrypted sessions using JWT values. +func checkAuth(res http.ResponseWriter, req *http.Request) bool { + store := networking.GetStore(networking.COOKIES_USER_AUTH) + + session_value, err := store.Read(res, req, "user") + if err != nil || session_value == nil { + return false + } + + username, ok := session_value.(string) + if !ok { + return false + } + + stored_secret, err := user.GetSecret(username) + if stored_secret == "" { + return false + } + + session_value, err = store.Read(res, req, "token") + if err != nil || session_value == nil { + return false + } + + tokenString, ok := session_value.(string) + if !ok { + return false + } + + keyfunc := func(t *jwt.Token) (interface{}, error) { + return []byte(stored_secret), nil + } + + p := jwt.Parser{ + ValidMethods: []string{"HS256", "HS384", "HS512"}, + } + t, err := p.ParseWithClaims(tokenString, &jwt.StandardClaims{}, keyfunc) + + if err != nil { + return false + } + + claims := t.Claims.(*jwt.StandardClaims) + if claims.Subject != username { + return false + } + + return true +} diff --git a/pkg/webhost/webhost.go b/pkg/webhost/webhost.go index 9117bf6..a62c872 100644 --- a/pkg/webhost/webhost.go +++ b/pkg/webhost/webhost.go @@ -5,14 +5,10 @@ import ( "io" "net/http" "os" - "strings" "github.com/Ennovar/gPanel/pkg/api" - "github.com/Ennovar/gPanel/pkg/api/user" "github.com/Ennovar/gPanel/pkg/logging" - "github.com/Ennovar/gPanel/pkg/networking" "github.com/Ennovar/gPanel/pkg/routing" - jwt "github.com/dgrijalva/jwt-go" ) type PrivateHost struct { @@ -26,35 +22,9 @@ func NewPrivateHost() PrivateHost { } } -// reqAuth function checks to see if the given path requires authentication. -func reqAuth(path string) bool { - path = strings.ToLower(path) - - dismissibleTypes := []string{".css", ".js"} - for _, t := range dismissibleTypes { - if strings.HasSuffix(path, t) { - return false - } - } - - dismissibleFiles := []string{ - "index.html", - "user_auth", - "user_register", - "user_logout", - } - for _, f := range dismissibleFiles { - if strings.HasSuffix(path, f) { - return false - } - } - - return true -} - // ServeHTTP function routes all requests for the private webhost server. It is used in the main // function inside of the http.ListenAndServe() function for the private webhost host. -func (priv *PrivateHost) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (priv *PrivateHost) ServeHTTP(res http.ResponseWriter, req *http.Request) { path := req.URL.Path[1:] if len(path) == 0 { path = (priv.Directory + "index.html") @@ -63,70 +33,13 @@ func (priv *PrivateHost) ServeHTTP(w http.ResponseWriter, req *http.Request) { } if reqAuth(path) { - store := networking.GetStore(networking.COOKIES_USER_AUTH) - - session_value, err := store.Read(w, req, "user") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - if session_value == nil { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - username, ok := session_value.(string) - if !ok { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - stored_secret, err := user.GetSecret(username) - if stored_secret == "" { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - session_value, err = store.Read(w, req, "token") - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - if session_value == nil { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - tokenString, ok := session_value.(string) - if !ok { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - keyfunc := func(t *jwt.Token) (interface{}, error) { - return []byte(stored_secret), nil - } - - p := jwt.Parser{ - ValidMethods: []string{"HS256", "HS384", "HS512"}, - } - t, err := p.ParseWithClaims(tokenString, &jwt.StandardClaims{}, keyfunc) - - if err != nil { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - claims := t.Claims.(*jwt.StandardClaims) - if claims.Subject != username { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + if !checkAuth(res, req) { + http.Error(res, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } } - isApi, _ := api.HandleAPI(path, w, req) + isApi, _ := api.HandleAPI(path, res, req) if isApi { // API methods handle HTTP logic from here @@ -136,7 +49,7 @@ func (priv *PrivateHost) ServeHTTP(w http.ResponseWriter, req *http.Request) { f, err := os.Open(path) if err != nil { - routing.HttpThrowStatus(http.StatusNotFound, w) + routing.HttpThrowStatus(http.StatusNotFound, res) logging.Console(logging.PRIVATE_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" rendered a 404 error.") return } @@ -144,16 +57,16 @@ func (priv *PrivateHost) ServeHTTP(w http.ResponseWriter, req *http.Request) { contentType, err := routing.GetContentType(path) if err != nil { - routing.HttpThrowStatus(http.StatusUnsupportedMediaType, w) + routing.HttpThrowStatus(http.StatusUnsupportedMediaType, res) logging.Console(logging.PUBLIC_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" content type could not be determined, 404 error.") return } - w.Header().Add("Content-Type", contentType) - _, err = io.Copy(w, f) + res.Header().Add("Content-Type", contentType) + _, err = io.Copy(res, f) if err != nil { - routing.HttpThrowStatus(http.StatusInternalServerError, w) + routing.HttpThrowStatus(http.StatusInternalServerError, res) logging.Console(logging.PUBLIC_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" rendered a 500 error.") return }