mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-08-14 06:37:12 +00:00
TRA-4157 fix ws auth (#669)
* Update socket_routes.go, user_controller.go, and 2 more files... * Update user_controller.go * Switch to http-only cookies for more security
This commit is contained in:
parent
6bab381280
commit
676e50b0b1
@ -47,9 +47,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int64) {
|
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int64) {
|
||||||
app.GET("/ws", func(c *gin.Context) {
|
app.GET("/ws", middlewares.RequiresAuth(), func(c *gin.Context) {
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, false, startTime)
|
websocketHandler(c.Writer, c.Request, eventHandlers, false, startTime)
|
||||||
}, middlewares.RequiresAuth())
|
})
|
||||||
|
|
||||||
app.GET("/wsTapper", func(c *gin.Context) { // TODO: add m2m authentication to this route
|
app.GET("/wsTapper", func(c *gin.Context) { // TODO: add m2m authentication to this route
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, true, startTime)
|
websocketHandler(c.Writer, c.Request, eventHandlers, true, startTime)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"mizuserver/pkg/providers"
|
"mizuserver/pkg/providers"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
@ -11,20 +13,44 @@ func Login(c *gin.Context) {
|
|||||||
if token, err := providers.PerformLogin(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil {
|
if token, err := providers.PerformLogin(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "bad login"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "bad login"})
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, gin.H{"token": token})
|
c.SetSameSite(http.SameSiteLaxMode)
|
||||||
|
c.SetCookie("x-session-token", *token, 3600, "/", "", false, true)
|
||||||
|
c.JSON(200, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Logout(c *gin.Context) {
|
func Logout(c *gin.Context) {
|
||||||
token := c.GetHeader("x-session-token")
|
token, err := c.Cookie("x-session-token")
|
||||||
if err := providers.Logout(token, c.Request.Context()); err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, http.ErrNoCookie) {
|
||||||
|
c.AbortWithStatusJSON(401, gin.H{"error": "could not find session cookie"})
|
||||||
|
} else {
|
||||||
|
logger.Log.Errorf("error reading cookie in logout %s", err)
|
||||||
|
c.AbortWithStatusJSON(500, gin.H{"error": "error occured while logging out, the session might still be valid"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = providers.Logout(token, c.Request.Context()); err != nil {
|
||||||
c.AbortWithStatusJSON(500, gin.H{"error": "error occured while logging out, the session might still be valid"})
|
c.AbortWithStatusJSON(500, gin.H{"error": "error occured while logging out, the session might still be valid"})
|
||||||
} else {
|
} else {
|
||||||
|
c.SetCookie("x-session-token", "", -1, "/", "", false, true)
|
||||||
c.JSON(200, "")
|
c.JSON(200, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(c *gin.Context) {
|
func Register(c *gin.Context) {
|
||||||
|
// only allow one user to be created without authentication
|
||||||
|
if IsInstallNeeded, err := providers.IsInstallNeeded(); err != nil {
|
||||||
|
logger.Log.Errorf("unknown internal while checking if install is needed %s", err)
|
||||||
|
c.AbortWithStatusJSON(500, gin.H{"error": "internal error occured while checking if install is needed"})
|
||||||
|
return
|
||||||
|
} else if !IsInstallNeeded {
|
||||||
|
c.AbortWithStatusJSON(401, gin.H{"error": "cannot register when install is not needed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if token, _, err, formErrorMessages := providers.RegisterUser(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil {
|
if token, _, err, formErrorMessages := providers.RegisterUser(c.PostForm("username"), c.PostForm("password"), c.Request.Context()); err != nil {
|
||||||
if formErrorMessages != nil {
|
if formErrorMessages != nil {
|
||||||
logger.Log.Infof("user attempted to register but had form errors %v %v", formErrorMessages, err)
|
logger.Log.Infof("user attempted to register but had form errors %v %v", formErrorMessages, err)
|
||||||
@ -34,6 +60,8 @@ func Register(c *gin.Context) {
|
|||||||
c.AbortWithStatusJSON(500, gin.H{"error": "internal error occured while registering"})
|
c.AbortWithStatusJSON(500, gin.H{"error": "internal error occured while registering"})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, gin.H{"token": token})
|
c.SetSameSite(http.SameSiteLaxMode)
|
||||||
|
c.SetCookie("x-session-token", *token, 3600, "/", "", false, true)
|
||||||
|
c.JSON(200, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,51 @@
|
|||||||
package middlewares
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"mizuserver/pkg/config"
|
"mizuserver/pkg/config"
|
||||||
"mizuserver/pkg/providers"
|
"mizuserver/pkg/providers"
|
||||||
"time"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/patrickmn/go-cache"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const cachedValidTokensRetainmentTime = time.Minute * 1
|
const errorMessage = "unknown authentication error occured"
|
||||||
|
|
||||||
var cachedValidTokens = cache.New(cachedValidTokensRetainmentTime, cachedValidTokensRetainmentTime)
|
|
||||||
|
|
||||||
func RequiresAuth() gin.HandlerFunc {
|
func RequiresAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
// auth is irrelevant for ephermeral mizu
|
// authentication is irrelevant for ephermeral mizu
|
||||||
if !config.Config.StandaloneMode {
|
if !config.Config.StandaloneMode {
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token := c.GetHeader("x-session-token")
|
token, err := c.Cookie("x-session-token")
|
||||||
if token == "" {
|
if err != nil {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "token header is empty"})
|
if errors.Is(err, http.ErrNoCookie) {
|
||||||
|
c.AbortWithStatusJSON(401, gin.H{"error": "could not find session cookie"})
|
||||||
|
} else {
|
||||||
|
logger.Log.Errorf("error reading cookie %s", err)
|
||||||
|
c.AbortWithStatusJSON(500, gin.H{"error": errorMessage})
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, isTokenCached := cachedValidTokens.Get(token); isTokenCached {
|
if token == "" {
|
||||||
c.Next()
|
c.AbortWithStatusJSON(401, gin.H{"error": "token cookie is empty"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTokenValid, err := providers.VerifyToken(token, c.Request.Context()); err != nil {
|
if isTokenValid, err := providers.VerifyToken(token, c.Request.Context()); err != nil {
|
||||||
logger.Log.Errorf("error verifying token %s", err)
|
logger.Log.Errorf("error verifying token %s", err)
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "unknown auth error occured"})
|
c.AbortWithStatusJSON(500, gin.H{"error": errorMessage})
|
||||||
return
|
return
|
||||||
} else if !isTokenValid {
|
} else if !isTokenValid {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "invalid token"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "invalid token"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedValidTokens.Set(token, true, cachedValidTokensRetainmentTime)
|
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@ export default class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.token = localStorage.getItem("token");
|
|
||||||
|
|
||||||
this.client = this.getAxiosClient();
|
this.client = this.getAxiosClient();
|
||||||
this.source = null;
|
this.source = null;
|
||||||
}
|
}
|
||||||
@ -143,7 +141,6 @@ export default class Api {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.client.post(`/user/register`, form);
|
const response = await this.client.post(`/user/register`, form);
|
||||||
this.persistToken(response.data.token);
|
|
||||||
return response;
|
return response;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.response.status === 400) {
|
if (e.response.status === 400) {
|
||||||
@ -164,32 +161,18 @@ export default class Api {
|
|||||||
form.append('password', password);
|
form.append('password', password);
|
||||||
|
|
||||||
const response = await this.client.post(`/user/login`, form);
|
const response = await this.client.post(`/user/login`, form);
|
||||||
if (response.status >= 200 && response.status < 300) {
|
|
||||||
this.persistToken(response.data.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
persistToken = (token) => {
|
|
||||||
this.token = token;
|
|
||||||
this.client = this.getAxiosClient();
|
|
||||||
localStorage.setItem('token', token);
|
|
||||||
}
|
|
||||||
|
|
||||||
logout = async () => {
|
logout = async () => {
|
||||||
await this.client.post(`/user/logout`);
|
await this.client.post(`/user/logout`);
|
||||||
this.persistToken(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAxiosClient = () => {
|
getAxiosClient = () => {
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: "application/json"
|
Accept: "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.token) {
|
|
||||||
headers['x-session-token'] = `${this.token}`; // we use `x-session-token` instead of `Authorization` because the latter is reserved by kubectl proxy, making mizu view not work
|
|
||||||
}
|
|
||||||
return axios.create({
|
return axios.create({
|
||||||
baseURL: apiURL,
|
baseURL: apiURL,
|
||||||
timeout: 31000,
|
timeout: 31000,
|
||||||
|
Loading…
Reference in New Issue
Block a user