Proxy working with authentications
This commit is contained in:
parent
28a44da3ad
commit
b561b94918
|
@ -29,13 +29,13 @@ import AnimateButton from '../../../components/@extended/AnimateButton';
|
|||
import RestartModal from './restart';
|
||||
|
||||
|
||||
export const CosmosInputText = ({ name, placeholder, label, formik }) => {
|
||||
export const CosmosInputText = ({ name, type, placeholder, label, formik }) => {
|
||||
return <Grid item xs={12}>
|
||||
<Stack spacing={1}>
|
||||
<InputLabel htmlFor={name}>{label}</InputLabel>
|
||||
<OutlinedInput
|
||||
id={name}
|
||||
type="text"
|
||||
type={type ? type : 'text'}
|
||||
value={formik.values[name]}
|
||||
name={name}
|
||||
onBlur={formik.handleBlur}
|
||||
|
|
|
@ -115,11 +115,11 @@ const ProxyManagement = () => {
|
|||
<RestartModal openModal={openModal} setOpenModal={setOpenModal} />
|
||||
{routes && routes.map((route,key) => (<>
|
||||
<RouteManagement routeConfig={route} setRouteConfig={(newRoute) => {
|
||||
routes[key] = newRoute;
|
||||
}}
|
||||
up={() => up(key)}
|
||||
down={() => down(key)}
|
||||
deleteRoute={() => deleteRoute(key)}
|
||||
routes[key] = newRoute;
|
||||
}}
|
||||
up={() => up(key)}
|
||||
down={() => down(key)}
|
||||
deleteRoute={() => deleteRoute(key)}
|
||||
/>
|
||||
<br /><br />
|
||||
</>))}
|
||||
|
|
|
@ -44,6 +44,7 @@ const RouteManagement = ({ routeConfig, setRouteConfig, up, down, deleteRoute })
|
|||
Mode: routeConfig.Mode,
|
||||
Target: routeConfig.Target,
|
||||
UseHost: routeConfig.UseHost,
|
||||
AuthEnabled: routeConfig.AuthEnabled,
|
||||
Host: routeConfig.Host,
|
||||
UsePathPrefix: routeConfig.UsePathPrefix,
|
||||
PathPrefix: routeConfig.PathPrefix,
|
||||
|
@ -145,11 +146,18 @@ const RouteManagement = ({ routeConfig, setRouteConfig, up, down, deleteRoute })
|
|||
/>}
|
||||
|
||||
<CosmosFormDivider title={'Security'}/>
|
||||
|
||||
<CosmosCheckbox
|
||||
name="AuthEnabled"
|
||||
label="Authentication Required"
|
||||
formik={formik}
|
||||
/>
|
||||
|
||||
<CosmosInputText
|
||||
name="Timeout"
|
||||
label="Timeout in milliseconds (0 for no timeout, at least 30000 or less recommended)"
|
||||
placeholder="Timeout"
|
||||
type="number"
|
||||
formik={formik}
|
||||
/>
|
||||
|
||||
|
@ -157,6 +165,7 @@ const RouteManagement = ({ routeConfig, setRouteConfig, up, down, deleteRoute })
|
|||
name="ThrottlePerMinute"
|
||||
label="Maximum number of requests Per Minute (0 for no limit, at least 100 or less recommended)"
|
||||
placeholder="Throttle Per Minute"
|
||||
type="number"
|
||||
formik={formik}
|
||||
/>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ FROM debian
|
|||
WORKDIR /app
|
||||
|
||||
COPY build/cosmos .
|
||||
COPY static .
|
||||
COPY static ./static
|
||||
|
||||
VOLUME /config
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"aliases": {
|
||||
"certificate": "sh generate-certificate.sh",
|
||||
"client": "g vite dev",
|
||||
"dockerdev": "g ci/build; g vite build --base=/ui/; docker build --tag cosmos-dev .",
|
||||
"start": "build/bin"
|
||||
}
|
||||
},
|
||||
|
@ -86,6 +87,6 @@
|
|||
},
|
||||
"description": "Cosmos Server",
|
||||
"name": "cosmos-server",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.6",
|
||||
"wrapInstallFolder": "src"
|
||||
}
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"strings"
|
||||
"strconv"
|
||||
"regexp"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
@ -75,6 +74,7 @@ func startHTTPSServer(router *mux.Router, tlsCert string, tlsKey string) {
|
|||
WriteTimeout: 0,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
Handler: router,
|
||||
DisableGeneralOptionsHandler: true,
|
||||
}
|
||||
|
||||
// start https server
|
||||
|
@ -99,19 +99,6 @@ func tokenMiddleware(next http.Handler) http.Handler {
|
|||
r.Header.Set("x-cosmos-user", u.Nickname)
|
||||
r.Header.Set("x-cosmos-role", strconv.Itoa((int)(u.Role)))
|
||||
|
||||
// TODO: If external application, remove the cookie from the request
|
||||
// to prevent leaking, and generate new JWT token
|
||||
if false {
|
||||
cookies := r.Header.Get("Cookie")
|
||||
// This prob dowsnt work
|
||||
cookieRemoveRegex := regexp.MustCompile(`jwttoken=[^;]*;`)
|
||||
cookies = cookieRemoveRegex.ReplaceAllString(cookies, "")
|
||||
r.Header.Set("Cookie", cookies)
|
||||
|
||||
// Replace the token with a application speicfic one
|
||||
r.Header.Set("x-cosmos-token", "1234567890")
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
@ -157,12 +144,11 @@ func StartServer() {
|
|||
|
||||
router.Use(middleware.Recoverer)
|
||||
router.Use(middleware.Logger)
|
||||
router.Use(tokenMiddleware)
|
||||
router.Use(utils.SetSecurityHeaders)
|
||||
|
||||
router.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/ui", http.StatusMovedPermanently)
|
||||
}))
|
||||
}))
|
||||
|
||||
srapi := router.PathPrefix("/cosmos").Subrouter()
|
||||
|
||||
|
@ -178,6 +164,7 @@ func StartServer() {
|
|||
srapi.HandleFunc("/api/users", user.UsersRoute)
|
||||
|
||||
// srapi.Use(utils.AcceptHeader("*/*"))
|
||||
srapi.Use(tokenMiddleware)
|
||||
srapi.Use(utils.CORSHeader(utils.GetMainConfig().HTTPConfig.Hostname))
|
||||
srapi.Use(utils.MiddlewareTimeout(20 * time.Second))
|
||||
srapi.Use(httprate.Limit(60, 1*time.Minute,
|
||||
|
|
|
@ -6,9 +6,44 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"time"
|
||||
"../utils"
|
||||
"../user"
|
||||
"strconv"
|
||||
"github.com/go-chi/httprate"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func tokenMiddleware(enabled bool) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Set("x-cosmos-user", "")
|
||||
r.Header.Set("x-cosmos-role", "")
|
||||
|
||||
u, err := user.RefreshUserToken(w, r)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r.Header.Set("x-cosmos-user", u.Nickname)
|
||||
r.Header.Set("x-cosmos-role", strconv.Itoa((int)(u.Role)))
|
||||
|
||||
ogcookies := r.Header.Get("Cookie")
|
||||
cookieRemoveRegex := regexp.MustCompile(`jwttoken=[^;]*;`)
|
||||
cookies := cookieRemoveRegex.ReplaceAllString(ogcookies, "")
|
||||
r.Header.Set("Cookie", cookies)
|
||||
|
||||
// Replace the token with a application speicfic one
|
||||
r.Header.Set("x-cosmos-token", "1234567890")
|
||||
|
||||
if(enabled) {
|
||||
utils.LoggedInOnlyWithRedirect(w, r);
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination *httputil.ReverseProxy) *mux.Route {
|
||||
var realDestination http.Handler
|
||||
realDestination = destination
|
||||
|
@ -49,6 +84,7 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination *ht
|
|||
}
|
||||
|
||||
origin.Handler(
|
||||
tokenMiddleware(route.AuthEnabled)(
|
||||
utils.CORSHeader(originCORS)(
|
||||
utils.MiddlewareTimeout(timeout * time.Millisecond)(
|
||||
httprate.Limit(throttlePerMinute, 1*time.Minute,
|
||||
|
@ -59,7 +95,7 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination *ht
|
|||
http.StatusTooManyRequests, "HTTP003")
|
||||
return
|
||||
}),
|
||||
)(realDestination))))
|
||||
)(realDestination)))))
|
||||
|
||||
return origin
|
||||
}
|
|
@ -95,6 +95,10 @@ func logOutUser(w http.ResponseWriter) {
|
|||
Name: "jwttoken",
|
||||
Value: "",
|
||||
Expires: time.Now().Add(-time.Hour * 24 * 365),
|
||||
Path: "/",
|
||||
Secure: true,
|
||||
HttpOnly: true,
|
||||
Domain: utils.GetMainConfig().HTTPConfig.Hostname,
|
||||
}
|
||||
|
||||
http.SetCookie(w, &cookie)
|
||||
|
@ -141,17 +145,11 @@ func SendUserToken(w http.ResponseWriter, user utils.User) {
|
|||
Name: "jwttoken",
|
||||
Value: tokenString,
|
||||
Expires: expiration,
|
||||
Path: "/",
|
||||
Secure: true,
|
||||
HttpOnly: true,
|
||||
// TODO: high level cookie for SSO
|
||||
// Should re-generate app specific cookies on subdomains
|
||||
// Domain: "yoursite.com",
|
||||
Domain: utils.GetMainConfig().HTTPConfig.Hostname,
|
||||
}
|
||||
// cookie2 := http.Cookie{
|
||||
// Name: "dummy",
|
||||
// Value: "asdasdadsasd",
|
||||
// Expires: expiration,
|
||||
// HttpOnly: true,
|
||||
// }
|
||||
|
||||
http.SetCookie(w, &cookie)
|
||||
// http.SetCookie(w, &cookie2)
|
||||
|
|
|
@ -39,7 +39,8 @@ func SetSecurityHeaders(next http.Handler) http.Handler {
|
|||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("X-Frame-Options", "DENY")
|
||||
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
||||
// w.Header().Set("Referrer-Policy", "no-referrer")
|
||||
w.Header().Set("X-Served-By-Cosmos", "1")
|
||||
w.Header().Set("Referrer-Policy", "no-referrer")
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
|
@ -48,6 +49,7 @@ func SetSecurityHeaders(next http.Handler) http.Handler {
|
|||
func CORSHeader(origin string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||
|
|
|
@ -95,6 +95,7 @@ type ProxyRouteConfig struct {
|
|||
ThrottlePerMinute int
|
||||
CORSOrigin string
|
||||
StripPathPrefix bool
|
||||
AuthEnabled bool
|
||||
Target string `validate:"required"`
|
||||
Mode ProxyMode
|
||||
}
|
||||
|
|
|
@ -197,8 +197,20 @@ func RestartServer() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
func LoggedInOnlyWithRedirect(w http.ResponseWriter, req *http.Request) error {
|
||||
userNickname := req.Header.Get("x-cosmos-user")
|
||||
role, _ := strconv.Atoi(req.Header.Get("x-cosmos-role"))
|
||||
isUserLoggedIn := role > 0
|
||||
|
||||
func loggedInOnly(w http.ResponseWriter, req *http.Request) error {
|
||||
if !isUserLoggedIn || userNickname == "" {
|
||||
Error("LoggedInOnlyWithRedirect: User is not logged in", nil)
|
||||
http.Redirect(w, req, "/ui/login?notlogged=1&redirect=" + req.URL.Path, http.StatusFound)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoggedInOnly(w http.ResponseWriter, req *http.Request) error {
|
||||
userNickname := req.Header.Get("x-cosmos-user")
|
||||
role, _ := strconv.Atoi(req.Header.Get("x-cosmos-role"))
|
||||
isUserLoggedIn := role > 0
|
||||
|
|
Loading…
Reference in a new issue