mirror of
https://github.com/donl/gPanel.git
synced 2026-06-30 06:12:06 -06:00
created session handler, session testing, implemented sessions to keep track of user authentication in the backend and implemented user logout api
This commit is contained in:
parent
bdd6074f3f
commit
8408d1f23b
7 changed files with 198 additions and 3 deletions
|
|
@ -51,6 +51,21 @@
|
|||
</table>
|
||||
</form>
|
||||
|
||||
<form class="api_form" method="POST" action="user_logout">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">gPanel Logout</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="2"><input type="submit" value="Logout"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
var form = document.getElementsByClassName('api_form');
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ func HandleAPI(path string, res http.ResponseWriter, req *http.Request) (bool, b
|
|||
return true, UserAuthentication(res, req)
|
||||
case "user_register":
|
||||
return true, UserRegistration(res, req)
|
||||
case "user_logout":
|
||||
return true, UserLogout(res, req)
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/Ennovar/gPanel/pkg/database"
|
||||
"github.com/Ennovar/gPanel/pkg/encryption"
|
||||
"github.com/Ennovar/gPanel/pkg/networking"
|
||||
)
|
||||
|
||||
// userRequestData struct is the structure of the JSON data to be
|
||||
|
|
@ -57,6 +58,14 @@ func UserAuthentication(res http.ResponseWriter, req *http.Request) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
store := networking.GetStore(networking.COOKIES_USER_AUTH)
|
||||
err = store.Set(res, req, "auth", true, (60 * 60 * 24))
|
||||
|
||||
if err != nil {
|
||||
http.Error(res, http.StatusText(500), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
res.WriteHeader(http.StatusNoContent)
|
||||
return true
|
||||
}
|
||||
|
|
@ -107,3 +116,23 @@ func UserRegistration(res http.ResponseWriter, req *http.Request) bool {
|
|||
res.WriteHeader(http.StatusNoContent)
|
||||
return true
|
||||
}
|
||||
|
||||
// UserRegistration function is accessed by an API call from the webhost root
|
||||
// by accessing /user_logout and sending it an empty POST request. This function will
|
||||
// delete the user-auth cookie session store
|
||||
func UserLogout(res http.ResponseWriter, req *http.Request) bool {
|
||||
if req.Method != "POST" {
|
||||
http.Error(res, req.Method+" HTTP method is unsupported for this API.", http.StatusMethodNotAllowed)
|
||||
return false
|
||||
}
|
||||
|
||||
store := networking.GetStore(networking.COOKIES_USER_AUTH)
|
||||
err := store.Delete(res, req)
|
||||
|
||||
if err != nil {
|
||||
http.Error(res, http.StatusText(500), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
77
pkg/networking/session_store.go
Normal file
77
pkg/networking/session_store.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Package networking contains various functions used to communicate between networks and
|
||||
// draw data from the client network.
|
||||
package networking
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
|
||||
var key = []byte("GbP=K4#f$khYuZpStK68GyHxGg$4@5K-")
|
||||
|
||||
const (
|
||||
COOKIES_USER_AUTH = "gpanel-webhost-user-auth"
|
||||
)
|
||||
|
||||
type store struct {
|
||||
handle *sessions.CookieStore
|
||||
cookieName string
|
||||
}
|
||||
|
||||
func GetStore(name string) store {
|
||||
sessionStore := store{
|
||||
handle: sessions.NewCookieStore(key),
|
||||
cookieName: name,
|
||||
}
|
||||
|
||||
return sessionStore
|
||||
}
|
||||
|
||||
func (s *store) Set(res http.ResponseWriter, req *http.Request, key string, value interface{}, expire int) error {
|
||||
session, err := s.handle.Get(req, s.cookieName)
|
||||
|
||||
if err != nil {
|
||||
http.Error(res, http.StatusText(500), http.StatusInternalServerError)
|
||||
return err
|
||||
}
|
||||
|
||||
session.Values[key] = value
|
||||
session.Options = &sessions.Options{
|
||||
Path: "/",
|
||||
MaxAge: expire,
|
||||
HttpOnly: true,
|
||||
}
|
||||
session.Save(req, res)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) Read(res http.ResponseWriter, req *http.Request, key string) (interface{}, error) {
|
||||
session, err := s.handle.Get(req, s.cookieName)
|
||||
|
||||
if err != nil {
|
||||
http.Error(res, http.StatusText(500), http.StatusInternalServerError)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value := session.Values[key]
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s *store) Delete(res http.ResponseWriter, req *http.Request) error {
|
||||
session, err := s.handle.Get(req, s.cookieName)
|
||||
|
||||
if err != nil {
|
||||
http.Error(res, http.StatusText(500), http.StatusInternalServerError)
|
||||
return err
|
||||
}
|
||||
|
||||
session.Options = &sessions.Options{
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
}
|
||||
|
||||
session.Save(req, res)
|
||||
return nil
|
||||
}
|
||||
51
pkg/networking/session_store_test.go
Normal file
51
pkg/networking/session_store_test.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Package networking contains various functions used to communicate between networks and
|
||||
// draw data from the client network.
|
||||
package networking
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// BUG(george-e-shaw-iv) Says statement coverage for network package is 0.0%, I think this
|
||||
// has something to do with the fact that I'm trying to test methods appended to a struct.
|
||||
func TestSessionStore(t *testing.T) {
|
||||
storeData := []struct {
|
||||
storeName string
|
||||
cookieName string
|
||||
key string
|
||||
value interface{}
|
||||
}{
|
||||
{"test-store-one", "test-cookie-one", "foo", "bar"},
|
||||
{"test-store-two", "test-cookie-two", "baz", true},
|
||||
{"test-store-three", "test-cookie-three", "foobar", 32},
|
||||
}
|
||||
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
for _, data := range storeData {
|
||||
store := GetStore(data.storeName)
|
||||
|
||||
err := store.Set(res, req, data.key, data.value, 60)
|
||||
if err != nil {
|
||||
t.Errorf("Error in session_store_test: %s", err.Error())
|
||||
}
|
||||
|
||||
val, err := store.Read(res, req, data.key)
|
||||
if err != nil {
|
||||
t.Errorf("Error in session_store_test: %s", err.Error())
|
||||
}
|
||||
|
||||
if reflect.TypeOf(data.value) != reflect.TypeOf(val) {
|
||||
t.Errorf("Error in session_store_test type checks, expected %s, got %s", reflect.TypeOf(data.value), reflect.TypeOf(val))
|
||||
}
|
||||
|
||||
err = store.Delete(res, req)
|
||||
if err != nil {
|
||||
t.Errorf("Error in session_store_test: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}))
|
||||
defer testServer.Close()
|
||||
}
|
||||
15
pkg/webhost/check_auth.go
Normal file
15
pkg/webhost/check_auth.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Package webhost handles the logic of the webhosting panel
|
||||
package webhost
|
||||
|
||||
import "strings"
|
||||
|
||||
var allowedUnauthorizedPathSuffixes = [...]string{"api_testing.html", "user_auth", "user_register"}
|
||||
|
||||
func CheckAuth(path string) bool {
|
||||
for _, suffix := range allowedUnauthorizedPathSuffixes {
|
||||
if strings.HasSuffix(path, suffix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -8,18 +8,17 @@ import (
|
|||
|
||||
"github.com/Ennovar/gPanel/pkg/api"
|
||||
"github.com/Ennovar/gPanel/pkg/logging"
|
||||
"github.com/Ennovar/gPanel/pkg/networking"
|
||||
"github.com/Ennovar/gPanel/pkg/routing"
|
||||
)
|
||||
|
||||
type PrivateHost struct {
|
||||
Auth int
|
||||
Directory string
|
||||
}
|
||||
|
||||
// NewPrivateHost returns a new PrivateHost type.
|
||||
func NewPrivateHost() PrivateHost {
|
||||
return PrivateHost{
|
||||
Auth: 1,
|
||||
Directory: "document_roots/webhost/",
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +33,14 @@ func (priv *PrivateHost) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
path = (priv.Directory + path)
|
||||
}
|
||||
|
||||
if priv.Auth != 1 {
|
||||
store := networking.GetStore(networking.COOKIES_USER_AUTH)
|
||||
val, err := store.Read(w, req, "auth")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if val != true && !CheckAuth(path) {
|
||||
routing.HttpThrowStatus(http.StatusUnauthorized, w)
|
||||
logging.Console(logging.PRIVATE_PREFIX, logging.NORMAL_LOG, "Path \""+path+"\" rendered a 401 error.")
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue