Allow all websocket connections, but require authentication before sending anything down the line
This commit is contained in:
parent
06780ac28f
commit
d583c1d53e
45
websocket.go
45
websocket.go
|
@ -19,6 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
AuthenticationSuccessEvent = "auth success"
|
||||||
TokenExpiringEvent = "token expiring"
|
TokenExpiringEvent = "token expiring"
|
||||||
TokenExpiredEvent = "token expired"
|
TokenExpiredEvent = "token expired"
|
||||||
AuthenticationEvent = "auth"
|
AuthenticationEvent = "auth"
|
||||||
|
@ -140,14 +141,11 @@ func (wsh *WebsocketHandler) TokenValid() error {
|
||||||
// Handle a request for a specific server websocket. This will handle inbound requests as well
|
// Handle a request for a specific server websocket. This will handle inbound requests as well
|
||||||
// as ensure that any console output is also passed down the wire on the socket.
|
// as ensure that any console output is also passed down the wire on the socket.
|
||||||
func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
token, err := ParseJWT([]byte(r.URL.Query().Get("token")))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := rt.upgrader.Upgrade(w, r, nil)
|
c, err := rt.upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Error(err)
|
zap.S().Errorw("error upgrading websocket", zap.Error(errors.WithStack(err)))
|
||||||
|
http.Error(w, "failed to upgrade websocket", http.StatusInternalServerError)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +167,7 @@ func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps http
|
||||||
Server: s,
|
Server: s,
|
||||||
Mutex: sync.Mutex{},
|
Mutex: sync.Mutex{},
|
||||||
Connection: c,
|
Connection: c,
|
||||||
JWT: token,
|
JWT: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOutput := func(data string) {
|
handleOutput := func(data string) {
|
||||||
|
@ -202,8 +200,6 @@ func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps http
|
||||||
s.AddListener(server.StatsEvent, &handleResourceUse)
|
s.AddListener(server.StatsEvent, &handleResourceUse)
|
||||||
defer s.RemoveListener(server.StatsEvent, &handleResourceUse)
|
defer s.RemoveListener(server.StatsEvent, &handleResourceUse)
|
||||||
|
|
||||||
s.Emit(server.StatusEvent, s.State)
|
|
||||||
|
|
||||||
// Sit here and check the time to expiration on the JWT every 30 seconds until
|
// Sit here and check the time to expiration on the JWT every 30 seconds until
|
||||||
// the token has expired. If we are within 3 minutes of the token expiring, send
|
// the token has expired. If we are within 3 minutes of the token expiring, send
|
||||||
// a notice over the socket that it is expiring soon. If it has expired, send that
|
// a notice over the socket that it is expiring soon. If it has expired, send that
|
||||||
|
@ -262,6 +258,19 @@ func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps http
|
||||||
// concurrent writes to the connection, which would cause a runtime panic and cause
|
// concurrent writes to the connection, which would cause a runtime panic and cause
|
||||||
// the program to crash out.
|
// the program to crash out.
|
||||||
func (wsh *WebsocketHandler) SendJson(v interface{}) error {
|
func (wsh *WebsocketHandler) SendJson(v interface{}) error {
|
||||||
|
// Do not send JSON down the line if the JWT on the connection is not
|
||||||
|
// valid!
|
||||||
|
if err := wsh.TokenValid(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return wsh.unsafeSendJson(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends JSON over the websocket connection, ignoring the authentication state of the
|
||||||
|
// socket user. Do not call this directly unless you are positive a response should be
|
||||||
|
// sent back to the client!
|
||||||
|
func (wsh *WebsocketHandler) unsafeSendJson(v interface{}) error {
|
||||||
wsh.Mutex.Lock()
|
wsh.Mutex.Lock()
|
||||||
defer wsh.Mutex.Unlock()
|
defer wsh.Mutex.Unlock()
|
||||||
|
|
||||||
|
@ -315,24 +324,40 @@ func (wsh *WebsocketHandler) HandleInbound(m WebsocketMessage) error {
|
||||||
return errors.New("cannot handle websocket message, not an inbound connection")
|
return errors.New("cannot handle websocket message, not an inbound connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.Event != AuthenticationEvent {
|
||||||
if err := wsh.TokenValid(); err != nil {
|
if err := wsh.TokenValid(); err != nil {
|
||||||
zap.S().Debugw("jwt token is no longer valid", zap.String("message", err.Error()))
|
zap.S().Debugw("jwt token is no longer valid", zap.String("message", err.Error()))
|
||||||
|
|
||||||
|
wsh.unsafeSendJson(WebsocketMessage{
|
||||||
|
Event: ErrorEvent,
|
||||||
|
Args: []string{"could not authenticate client: " + err.Error()},
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch m.Event {
|
switch m.Event {
|
||||||
case AuthenticationEvent:
|
case AuthenticationEvent:
|
||||||
{
|
{
|
||||||
token, err := ParseJWT([]byte(strings.Join(m.Args, "")))
|
token, err := ParseJWT([]byte(strings.Join(m.Args, "")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if token.HasPermission(PermissionConnect) {
|
if token.HasPermission(PermissionConnect) {
|
||||||
wsh.JWT = token
|
wsh.JWT = token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On every authentication event, send the current server status back
|
||||||
|
// to the client. :)
|
||||||
|
wsh.Server.Emit(server.StatusEvent, wsh.Server.State)
|
||||||
|
|
||||||
|
wsh.unsafeSendJson(WebsocketMessage{
|
||||||
|
Event: AuthenticationSuccessEvent,
|
||||||
|
Args: []string{},
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case SetStateEvent:
|
case SetStateEvent:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user