Skip to content

Commit

Permalink
Merge pull request #294 from jumpserver/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
LeeEirc authored May 21, 2020
2 parents d85989d + 6de49f0 commit 26a3cef
Show file tree
Hide file tree
Showing 16 changed files with 245 additions and 220 deletions.
23 changes: 17 additions & 6 deletions pkg/auth/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult)
ctx.SetValue(model.ContextKeyClient, userClient)
}
userClient.SetOption(service.Password(password), service.PublicKey(publicKey))
logger.Infof("SSH conn[%s] authenticating user %s %s", ctx.SessionID(), username, authMethod)
user, authStatus := userClient.Authenticate(ctx)
switch authStatus {
case service.AuthMFARequired:
Expand All @@ -59,7 +60,8 @@ func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult)
default:
action = actionFailed
}
logger.Infof("%s %s for %s from %s", action, authMethod, username, remoteAddr)
logger.Infof("SSH conn[%s] %s %s for %s from %s", ctx.SessionID(),
action, authMethod, username, remoteAddr)
return

}
Expand Down Expand Up @@ -95,7 +97,8 @@ func CheckMFA(ctx ssh.Context, challenger gossh.KeyboardInteractiveChallenge) (r

client, ok := ctx.Value(model.ContextKeyClient).(*service.SessionClient)
if !ok {
logger.Errorf("User %s Mfa Auth failed: not found session client.", username, )
logger.Errorf("SSH conn[%s] user %s Mfa Auth failed: not found session client.",
ctx.SessionID(), username)
return
}
value, ok := ctx.Value(model.ContextKeyConfirmRequired).(*bool)
Expand All @@ -109,42 +112,50 @@ func CheckMFA(ctx ssh.Context, challenger gossh.KeyboardInteractiveChallenge) (r
if confirmAction {
client.CancelConfirm()
}
logger.Errorf("User %s happened err: %s", username, err)
logger.Errorf("SSH conn[%s] user %s happened err: %s", ctx.SessionID(), username, err)
return
}
if confirmAction {
switch strings.TrimSpace(strings.ToLower(answers[0])) {
case "yes", "y", "":
logger.Infof("SSH conn[%s] checking user %s login confirm", ctx.SessionID(), username)
user, authStatus := client.CheckConfirm(ctx)
switch authStatus {
case service.AuthSuccess:
res = ssh.AuthSuccessful
ctx.SetValue(model.ContextKeyUser, &user)
logger.Infof("SSH conn[%s] checking user %s login confirm success", ctx.SessionID(), username)
return
}
case "no", "n":
logger.Infof("SSH conn[%s] user %s cancel login", ctx.SessionID(), username)
client.CancelConfirm()
default:
return
}
failed := true
ctx.SetValue(model.ContextKeyConfirmFailed, &failed)
logger.Infof("SSH conn[%s] checking user %s login confirm failed", ctx.SessionID(), username)
return
}
mfaCode := answers[0]
logger.Infof("SSH conn[%s] checking user %s mfa code", ctx.SessionID(), username)
user, authStatus := client.CheckUserOTP(ctx, mfaCode)
switch authStatus {
case service.AuthSuccess:
res = ssh.AuthSuccessful
ctx.SetValue(model.ContextKeyUser, &user)
logger.Infof("%s MFA for %s from %s", actionAccepted, username, remoteAddr)
logger.Infof("SSH conn[%s] %s MFA for %s from %s", ctx.SessionID(),
actionAccepted, username, remoteAddr)
case service.AuthConfirmRequired:
res = ssh.AuthPartiallySuccessful
required := true
ctx.SetValue(model.ContextKeyConfirmRequired, &required)
logger.Infof("%s MFA for %s from %s", actionPartialAccepted, username, remoteAddr)
logger.Infof("SSH conn[%s] %s MFA for %s from %s", ctx.SessionID(),
actionPartialAccepted, username, remoteAddr)
default:
logger.Errorf("%s MFA for %s from %s", actionFailed, username, remoteAddr)
logger.Errorf("SSH conn[%s] %s MFA for %s from %s", ctx.SessionID(),
actionFailed, username, remoteAddr)
}
return
}
Expand Down
28 changes: 6 additions & 22 deletions pkg/httpd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,18 @@ package httpd

import (
"io"
"sync"

"github.com/gliderlabs/ssh"
"github.com/kataras/neffos"
)

type Client struct {
Uuid string
Cid string
addr string
WinChan chan ssh.Window
UserRead io.Reader
UserWrite io.WriteCloser
Conn *UserWebsocketConn
Closed bool
pty ssh.Pty
mu *sync.RWMutex
}

func (c *Client) WinCh() <-chan ssh.Window {
Expand All @@ -30,42 +25,31 @@ func (c *Client) LoginFrom() string {
}

func (c *Client) RemoteAddr() string {
return c.addr
return c.Conn.Addr
}

func (c *Client) Read(p []byte) (n int, err error) {
return c.UserRead.Read(p)
}

func (c *Client) Write(p []byte) (n int, err error) {
c.mu.RLock()
defer c.mu.RUnlock()
if c.Closed {
return
if _, ok := c.Conn.GetClient(c.Uuid); ok {
data := DataMsg{Data: string(p), Room: c.Uuid}
c.Conn.SendDataEvent(neffos.Marshal(data))
return len(p), nil
}
data := DataMsg{Data: string(p), Room: c.Uuid}
n = len(p)
c.Conn.SendDataEvent(neffos.Marshal(data))
return
return 0, io.EOF
}

func (c *Client) Pty() ssh.Pty {
return c.pty
}

func (c *Client) Close() (err error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.Closed {
return
}
c.Closed = true
return c.UserWrite.Close()
}

func (c *Client) SetWinSize(size ssh.Window) {
c.mu.RLock()
defer c.mu.RUnlock()
select {
case c.WinChan <- size:
default:
Expand Down
2 changes: 1 addition & 1 deletion pkg/httpd/neffosws.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ func neffosOnDisconnect(c *neffos.Conn) {
if conn, ok := websocketManager.GetUserCon(c.ID()); ok {
conn.Close()
websocketManager.DeleteUserCon(c.ID())
logger.Infof("User %s ws %s disconnect.", conn.User.Username, c.ID())
logger.Infof("User %s ws %s disconnect.", conn.User.Name, c.ID())
}
}
83 changes: 23 additions & 60 deletions pkg/httpd/websshws.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ import (
"fmt"
"html/template"
"io"
"net"
"net/http"
"strings"
"sync"

"github.com/gliderlabs/ssh"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -74,8 +72,8 @@ func OnNamespaceDisconnect(c *neffos.NSConn, msg neffos.Message) (err error) {
}

// OnHostHandler 当用户连接Host时触发
func OnHostHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
websocketID := c.Conn.ID()
func OnHostHandler(ns *neffos.NSConn, msg neffos.Message) (err error) {
websocketID := ns.Conn.ID()
logger.Debugf("Ws %s fire host event", websocketID)
userConn, ok := websocketManager.GetUserCon(websocketID)
if !ok {
Expand All @@ -84,7 +82,6 @@ func OnHostHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
return errors.New(errMsg)
}

cc := c.Conn
var message HostMsg
err = msg.Unmarshal(&message)
if err != nil {
Expand All @@ -107,6 +104,7 @@ func OnHostHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
}
roomID := uuid.NewV4().String()
emitMsg := RoomMsg{roomID, secret}

userConn.SendRoomEvent(neffos.Marshal(emitMsg))
var databaseAsset model.Database
var asset model.Asset
Expand Down Expand Up @@ -135,60 +133,38 @@ func OnHostHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
}
connectName = asset.Hostname
}
logger.Infof("Ws %s start to connect %s", websocketID, connectName)
currentUser, ok := cc.Get("currentUser").(*model.User)
if !ok {
err = errors.New("not found current user")
dataMsg := DataMsg{Room: roomID, Data: err.Error()}
logger.Errorf("Host Event: ws %s no found user.", websocketID)
userConn.SendDataEvent(neffos.Marshal(dataMsg))
return err
}
userR, userW := io.Pipe()
var addr string
request := cc.Socket().Request()
header := request.Header
remoteAddr := header.Get("X-Forwarded-For")
if remoteAddr == "" {
if host, _, err := net.SplitHostPort(request.RemoteAddr); err == nil {
addr = host
} else {
addr = request.RemoteAddr
}
} else {
addr = strings.Split(remoteAddr, ",")[0]
}

client := &Client{
Uuid: roomID, addr: addr,
Uuid: roomID,
WinChan: make(chan ssh.Window, 100), Conn: userConn,
UserRead: userR, UserWrite: userW, mu: new(sync.RWMutex),
UserRead: userR, UserWrite: userW,
pty: ssh.Pty{Term: "xterm", Window: win},
}
client.WinChan <- win
logger.Infof("Conn[%s] start to connect %s", roomID, connectName)
var proxySrv proxyServer
switch strings.ToLower(message.HostType) {
case "database":
proxySrv = &proxy.DBProxyServer{
UserConn: client,
User: currentUser,
User: userConn.User,
Database: &databaseAsset,
SystemUser: &systemUser,
}
default:
proxySrv = &proxy.ProxyServer{
UserConn: client, User: currentUser,
UserConn: client, User: userConn.User,
Asset: &asset, SystemUser: &systemUser,
}
}
go func() {
logger.Infof("Ws %s add client %s to proxy", websocketID, client.Uuid)
logger.Infof("Ws %s add Conn[%s] to proxy", websocketID, client.Uuid)
userConn.AddClient(client.Uuid, client)
proxySrv.Proxy()
logoutMsg := LogoutMsg{Room: roomID}
userConn.SendLogoutEvent(neffos.Marshal(logoutMsg))
userConn.DeleteClient(client.Uuid)
logger.Infof("Ws %s remove client %s to proxy", websocketID, client.Uuid)
logger.Infof("Ws %s remove Conn[%s]", websocketID, client.Uuid)
}()
return nil
}
Expand Down Expand Up @@ -271,7 +247,7 @@ func OnResizeHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
logger.Errorf("Resize Event: ws %s unmarshal msg err %s", c.Conn.ID(), err)
return
}
logger.Debugf("Resize Event: ws %s resize windows to %d*%d", c.Conn.ID(), message.Width, message.Height)
logger.Infof("Resize Event: ws %s resize windows to %d*%d", c.Conn.ID(), message.Width, message.Height)
winSize := ssh.Window{Height: message.Height, Width: message.Width}
if conn, ok := websocketManager.GetUserCon(c.Conn.ID()); ok {
conn.ReceiveResizeEvent(winSize)
Expand All @@ -290,7 +266,7 @@ func OnLogoutHandler(c *neffos.NSConn, msg neffos.Message) (err error) {
logger.Errorf("Logout event: ws %s unmarshal msg err: %s", c.Conn.ID(), err)
return
}
logger.Debugf("Logout event: ws %s logout clientID %s", c.Conn.ID(), clientID)
logger.Infof("Logout event: ws %s logout Conn[%s]", c.Conn.ID(), clientID)
if conn, ok := websocketManager.GetUserCon(c.Conn.ID()); ok {
conn.ReceiveLogoutEvent(clientID)
return nil
Expand All @@ -312,12 +288,11 @@ func OnShareRoom(ns *neffos.NSConn, msg neffos.Message) (err error) {
logger.Debugf("Ws %s fire ShareRoom", websocketID)
userConn, ok := websocketManager.GetUserCon(websocketID)
if !ok {
errMsg := fmt.Sprintf("Websocket %s should fire connected first.", websocketID)
errMsg := fmt.Sprintf("Ws %s should fire connected first.", websocketID)
logger.Errorf(errMsg)
return errors.New(errMsg)
}

cc := ns.Conn
var shareRoomMsg struct {
ShareRoomID string `json:"shareRoomID"`
Secret string `json:"secret"`
Expand All @@ -328,27 +303,14 @@ func OnShareRoom(ns *neffos.NSConn, msg neffos.Message) (err error) {
return err
}
userR, userW := io.Pipe()
var addr string
request := cc.Socket().Request()
header := request.Header
remoteAddr := header.Get("X-Forwarded-For")
if remoteAddr == "" {
if host, _, err := net.SplitHostPort(request.RemoteAddr); err == nil {
addr = host
} else {
addr = request.RemoteAddr
}
} else {
addr = strings.Split(remoteAddr, ",")[0]
}
uid := uuid.NewV4().String()
emitMsg := RoomMsg{uid, shareRoomMsg.Secret}
userConn.SendRoomEvent(neffos.Marshal(emitMsg))
win := ssh.Window{Height: 24, Width: 80}
client := &Client{
Uuid: uid, addr: addr,
Uuid: uid,
WinChan: make(chan ssh.Window, 100), Conn: userConn,
UserRead: userR, UserWrite: userW, mu: new(sync.RWMutex),
UserRead: userR, UserWrite: userW,
pty: ssh.Pty{Term: "xterm", Window: win},
}
client.WinChan <- win
Expand All @@ -365,7 +327,7 @@ func JoinRoom(c *Client, roomID string) {
logoutMsg := LogoutMsg{Room: c.Uuid}

if err != nil {
logger.Errorf("Ws Join Room err: %s", err)
logger.Errorf("Conn[%s] Join Room err: %s", c.ID(), err)
logoutMsg.Data = fmt.Sprintf("Join Session err: %s", err)
logoutData, _ := json.Marshal(logoutMsg)
c.Conn.SendLogoutEvent(logoutData)
Expand All @@ -374,7 +336,7 @@ func JoinRoom(c *Client, roomID string) {
defer ex.LeaveRoom(room, roomID)

if !c.Conn.CheckShareRoomReadPerm(roomID) {
logger.Error("Ws has no pem to join room")
logger.Errorf("Conn[%s] has no pem to join room", c.ID())
logoutMsg.Data = fmt.Sprintf("You have no perm to join room %s", roomID)
logoutData, _ := json.Marshal(logoutMsg)
c.Conn.SendLogoutEvent(logoutData)
Expand All @@ -384,7 +346,6 @@ func JoinRoom(c *Client, roomID string) {
for {
msg, ok := <-roomChan
if !ok {
logger.Infof("User %s exit room %s by roomChan closed", c.Conn.User.Name, roomID)
break
}
switch msg.Event {
Expand All @@ -400,22 +361,23 @@ func JoinRoom(c *Client, roomID string) {
case model.WindowsEvent, model.PingEvent:
continue
default:
logger.Errorf("User %s in room %s receive unknown event %s", c.Conn.User.Name, roomID, msg.Event)
logger.Errorf("Conn[%s] receive unknown room event %s", c.Conn.User.Name, roomID, msg.Event)

}
logger.Infof("User %s stop receive msg from room %s by %s", c.Conn.User.Name, roomID, msg.Event)
logger.Infof("Conn[%s] stop receive msg from room %s by %s", c.ID(), roomID, msg.Event)
break

}
_ = c.Close()

c.Conn.DeleteClient(c.Uuid)
logger.Infof("Conn[%s] User %s exit room %s", c.ID(), c.Conn.User.Name, roomID)
}()

buf := make([]byte, 1024)
for {
nr, err := c.Read(buf)
if err != nil {
logger.Errorf("User %s exit share room %s by %s", c.Conn.User.Name, roomID, err)
logger.Errorf("Conn[%s] User %s exit share room %s by %s", c.Conn.User.Name, roomID, err)
break
}
// checkout user write pem
Expand All @@ -427,5 +389,6 @@ func JoinRoom(c *Client, roomID string) {
Body: buf[:nr],
}
room.Publish(msg)
logger.Infof("User %s published DataEvent to room %s", c.Conn.User.Name, roomID)
}
}
Loading

0 comments on commit 26a3cef

Please sign in to comment.