Commit 84baeb09 authored by ibuler's avatar ibuler

[Update] 解决MFA的问题

parent 4ae96f1c
package main
import (
"bytes"
"fmt"
"golang.org/x/crypto/ssh/terminal"
"io"
"io/ioutil"
"os"
)
var f, _ = os.Create("/tmp/new.txt")
var buf, _ = ioutil.ReadFile("/tmp/cmd.text")
type CmdRwParser struct {
content []byte
}
func (c *CmdRwParser) Read(b []byte) (int, error) {
for i, v := range c.content {
b[i] = v
}
fmt.Printf("Read %s\n", b)
return len(c.content), io.EOF
}
func (c *CmdRwParser) Write(b []byte) (int, error) {
fmt.Printf("Write %s\n", b)
return len(b), nil
}
func main() {
nb := new(bytes.Buffer)
term := terminal.NewTerminal(nb, ">")
nb.Write(buf)
nb.Write([]byte("\r"))
fmt.Printf("Buf: %s\n", buf)
line, _ := term.ReadLine()
f.WriteString(line)
fmt.Printf("Line: %s\n", []byte(line))
fmt.Println(".......................")
fmt.Printf(nb.String())
f.Close()
}
package auth package auth
import ( import (
"cocogo/pkg/model"
"fmt"
"strings" "strings"
"github.com/ibuler/ssh" "github.com/ibuler/ssh"
...@@ -12,36 +14,45 @@ import ( ...@@ -12,36 +14,45 @@ import (
"cocogo/pkg/service" "cocogo/pkg/service"
) )
func checkAuth(ctx ssh.Context, password, publicKey string) (ok bool) { func checkAuth(ctx ssh.Context, password, publicKey string) (res ssh.AuthResult) {
username := ctx.User() username := ctx.User()
remoteAddr := strings.Split(ctx.RemoteAddr().String(), ":")[0] remoteAddr := strings.Split(ctx.RemoteAddr().String(), ":")[0]
user := service.Authenticate(username, password, publicKey, remoteAddr, "T") user, err := service.Authenticate(username, password, publicKey, remoteAddr, "T")
authMethod := "publickey" authMethod := "publickey"
action := "Accepted" action := "Accepted"
res = ssh.AuthFailed
if password != "" { if password != "" {
authMethod = "password" authMethod = "password"
} }
if user.Id == "" { if err != nil {
action = "Failed" action = "Failed"
} else { } else {
ctx.SetValue(cctx.ContextKeyUser, user) ctx.SetValue(cctx.ContextKeyUser, user)
ok = true res = ssh.AuthPartiallySuccessful
} }
logger.Infof("%s %s for %s from %s", action, authMethod, username, remoteAddr) logger.Infof("%s %s for %s from %s", action, authMethod, username, remoteAddr)
return ok return res
} }
func CheckUserPassword(ctx ssh.Context, password string) bool { func CheckUserPassword(ctx ssh.Context, password string) ssh.AuthResult {
ok := checkAuth(ctx, password, "") res := checkAuth(ctx, password, "")
return ok return res
} }
func CheckUserPublicKey(ctx ssh.Context, key ssh.PublicKey) bool { func CheckUserPublicKey(ctx ssh.Context, key ssh.PublicKey) ssh.AuthResult {
b := key.Marshal() b := key.Marshal()
publicKey := common.Base64Encode(string(b)) publicKey := common.Base64Encode(string(b))
return checkAuth(ctx, "", publicKey) return checkAuth(ctx, "", publicKey)
} }
func CheckMFA(ctx ssh.Context, challenger gossh.KeyboardInteractiveChallenge) bool { func CheckMFA(ctx ssh.Context, challenger gossh.KeyboardInteractiveChallenge) ssh.AuthResult {
return false answers, err := challenger("admin", "> ", []string{"MFA"}, []bool{true})
if err != nil {
return ssh.AuthFailed
}
fmt.Println(answers)
//ok := checkAuth(ctx, "admin", "")
ctx.SetValue(cctx.ContextKeyUser, &model.User{Username: "admin", Name: "admin"})
return ssh.AuthSuccessful
} }
...@@ -2,6 +2,7 @@ package cctx ...@@ -2,6 +2,7 @@ package cctx
import ( import (
"context" "context"
"github.com/ibuler/ssh" "github.com/ibuler/ssh"
"cocogo/pkg/model" "cocogo/pkg/model"
......
package common package common
import "os"
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
package config package config
import ( import (
"cocogo/pkg/logger"
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"strings" "strings"
...@@ -73,7 +73,7 @@ func (c *Config) LoadFromJSON(body []byte) error { ...@@ -73,7 +73,7 @@ func (c *Config) LoadFromJSON(body []byte) error {
defer c.mux.Unlock() defer c.mux.Unlock()
err := json.Unmarshal(body, c) err := json.Unmarshal(body, c)
if err != nil { if err != nil {
fmt.Println("Load yaml err") logger.Error("Config load yaml error")
os.Exit(1) os.Exit(1)
} }
return nil return nil
...@@ -113,9 +113,9 @@ var Conf = &Config{ ...@@ -113,9 +113,9 @@ var Conf = &Config{
SSHTimeout: 60, SSHTimeout: 60,
HTTPPort: 5000, HTTPPort: 5000,
AccessKey: "", AccessKey: "",
AccessKeyFile: "access_key", AccessKeyFile: "data/keys/.access_key",
LogLevel: "DEBUG", LogLevel: "DEBUG",
HostKeyFile: "host_key", HostKeyFile: "data/keys/host_key",
HostKey: "", HostKey: "",
RootPath: rootPath, RootPath: rootPath,
Comment: "Coco", Comment: "Coco",
......
...@@ -2,7 +2,6 @@ package proxy ...@@ -2,7 +2,6 @@ package proxy
import ( import (
"bytes" "bytes"
"cocogo/pkg/recorder"
"sync" "sync"
"time" "time"
...@@ -46,8 +45,8 @@ type Parser struct { ...@@ -46,8 +45,8 @@ type Parser struct {
counter int counter int
cmdFilterRules []model.SystemUserFilterRule cmdFilterRules []model.SystemUserFilterRule
commandRecorder *recorder.CommandRecorder commandRecorder *CommandRecorder
replayRecorder *recorder.ReplyRecorder replayRecorder *ReplyRecorder
} }
func (p *Parser) Initial() { func (p *Parser) Initial() {
...@@ -174,13 +173,13 @@ func (p *Parser) SetCMDFilterRules(rules []model.SystemUserFilterRule) { ...@@ -174,13 +173,13 @@ func (p *Parser) SetCMDFilterRules(rules []model.SystemUserFilterRule) {
p.cmdFilterRules = rules p.cmdFilterRules = rules
} }
func (p *Parser) SetReplayRecorder(recorder *recorder.ReplyRecorder) { func (p *Parser) SetReplayRecorder(recorder *ReplyRecorder) {
p.replayRecorder = recorder p.replayRecorder = recorder
} }
func (p *Parser) recordCommand() { func (p *Parser) recordCommand() {
cmd := &recorder.Command{ cmd := &Command{
SessionId: p.session.Id, SessionId: p.session.Id,
OrgId: p.session.Org, OrgId: p.session.Org,
Input: p.command, Input: p.command,
...@@ -193,7 +192,7 @@ func (p *Parser) recordCommand() { ...@@ -193,7 +192,7 @@ func (p *Parser) recordCommand() {
p.commandRecorder.Record(cmd) p.commandRecorder.Record(cmd)
} }
func (p *Parser) SetCommandRecorder(recorder *recorder.CommandRecorder) { func (p *Parser) SetCommandRecorder(recorder *CommandRecorder) {
p.commandRecorder = recorder p.commandRecorder = recorder
} }
......
package proxy package proxy
import ( import (
"cocogo/pkg/recorder"
"fmt" "fmt"
"io" "io"
"strings" "strings"
...@@ -47,10 +46,11 @@ func (p *ProxyServer) validatePermission() bool { ...@@ -47,10 +46,11 @@ func (p *ProxyServer) validatePermission() bool {
func (p *ProxyServer) getServerConn() (srvConn ServerConnection, err error) { func (p *ProxyServer) getServerConn() (srvConn ServerConnection, err error) {
srvConn = &ServerSSHConnection{ srvConn = &ServerSSHConnection{
host: "192.168.244.145", host: "192.168.244.185",
port: "22", port: "22",
user: "root", user: "web",
password: "redhat", password: "redhat",
timeout: config.Conf.SSHTimeout,
} }
pty, _, ok := p.Session.Pty() pty, _, ok := p.Session.Pty()
if !ok { if !ok {
...@@ -61,7 +61,7 @@ func (p *ProxyServer) getServerConn() (srvConn ServerConnection, err error) { ...@@ -61,7 +61,7 @@ func (p *ProxyServer) getServerConn() (srvConn ServerConnection, err error) {
go p.sendConnectingMsg(done) go p.sendConnectingMsg(done)
err = srvConn.Connect(pty.Window.Height, pty.Window.Width, pty.Term) err = srvConn.Connect(pty.Window.Height, pty.Window.Width, pty.Term)
_, _ = io.WriteString(p.Session, "\r\n") _, _ = io.WriteString(p.Session, "\r\n")
done <- struct{}{} close(done)
return return
} }
...@@ -100,10 +100,8 @@ func (p *ProxyServer) Proxy() { ...@@ -100,10 +100,8 @@ func (p *ProxyServer) Proxy() {
logger.Error("Get system user filter rule error: ", err) logger.Error("Get system user filter rule error: ", err)
} }
sw.parser.SetCMDFilterRules(cmdRules) sw.parser.SetCMDFilterRules(cmdRules)
replayRecorder := recorder.NewReplyRecord(sw.Id) replayRecorder := NewReplyRecord(sw.Id)
sw.parser.SetReplayRecorder(replayRecorder) sw.parser.SetReplayRecorder(replayRecorder)
cmdR
sw.parser.SetCommandRecorder()
_ = sw.Bridge() _ = sw.Bridge()
_ = srvConn.Close() _ = srvConn.Close()
} }
...@@ -29,7 +29,7 @@ type ServerSSHConnection struct { ...@@ -29,7 +29,7 @@ type ServerSSHConnection struct {
password string password string
privateKey string privateKey string
privateKeyPath string privateKeyPath string
timeout time.Duration timeout int
Proxy *ServerSSHConnection Proxy *ServerSSHConnection
client *gossh.Client client *gossh.Client
...@@ -61,7 +61,7 @@ func (sc *ServerSSHConnection) Port() string { ...@@ -61,7 +61,7 @@ func (sc *ServerSSHConnection) Port() string {
} }
func (sc *ServerSSHConnection) Timeout() time.Duration { func (sc *ServerSSHConnection) Timeout() time.Duration {
return sc.timeout return time.Duration(sc.timeout) * time.Second
} }
func (sc *ServerSSHConnection) String() string { func (sc *ServerSSHConnection) String() string {
...@@ -93,7 +93,7 @@ func (sc *ServerSSHConnection) Config() (config *gossh.ClientConfig, err error) ...@@ -93,7 +93,7 @@ func (sc *ServerSSHConnection) Config() (config *gossh.ClientConfig, err error)
User: sc.user, User: sc.user,
Auth: authMethods, Auth: authMethods,
HostKeyCallback: gossh.InsecureIgnoreHostKey(), HostKeyCallback: gossh.InsecureIgnoreHostKey(),
Timeout: sc.timeout, Timeout: sc.Timeout(),
} }
return config, nil return config, nil
} }
...@@ -158,6 +158,7 @@ func (sc *ServerSSHConnection) invokeShell(h, w int, term string) (err error) { ...@@ -158,6 +158,7 @@ func (sc *ServerSSHConnection) invokeShell(h, w int, term string) (err error) {
func (sc *ServerSSHConnection) Connect(h, w int, term string) (err error) { func (sc *ServerSSHConnection) Connect(h, w int, term string) (err error) {
_, err = sc.connect() _, err = sc.connect()
fmt.Println("error")
if err != nil { if err != nil {
return return
} }
......
package proxy package proxy
import ( import (
"cocogo/pkg/logger"
"context" "context"
"time"
"github.com/ibuler/ssh" "github.com/ibuler/ssh"
"github.com/satori/go.uuid" "github.com/satori/go.uuid"
"time"
"cocogo/pkg/logger"
) )
func NewSwitch(userConn UserConnection, serverConn ServerConnection) (sw *Session) { func NewSwitch(userConn UserConnection, serverConn ServerConnection) (sw *Session) {
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"strings" "strings"
"cocogo/pkg/common" "cocogo/pkg/common"
...@@ -61,6 +62,13 @@ func (ak *AccessKey) LoadAccessKeyFromFile(keyPath string) error { ...@@ -61,6 +62,13 @@ func (ak *AccessKey) LoadAccessKeyFromFile(keyPath string) error {
} }
func (ak *AccessKey) SaveToFile() error { func (ak *AccessKey) SaveToFile() error {
keyDir := path.Dir(ak.Path)
if !common.FileExists(keyDir) {
err := os.MkdirAll(keyDir, os.ModePerm)
if err != nil {
return err
}
}
f, err := os.Create(ak.Path) f, err := os.Create(ak.Path)
defer f.Close() defer f.Close()
if err != nil { if err != nil {
...@@ -74,7 +82,6 @@ func (ak *AccessKey) SaveToFile() error { ...@@ -74,7 +82,6 @@ func (ak *AccessKey) SaveToFile() error {
} }
func (ak *AccessKey) Register(times int) error { func (ak *AccessKey) Register(times int) error {
fmt.Println(config.Conf.Name)
name := config.Conf.Name name := config.Conf.Name
token := config.Conf.BootstrapToken token := config.Conf.BootstrapToken
comment := "Coco" comment := "Coco"
......
...@@ -7,7 +7,7 @@ import ( ...@@ -7,7 +7,7 @@ import (
"cocogo/pkg/model" "cocogo/pkg/model"
) )
func Authenticate(username, password, publicKey, remoteAddr, loginType string) (user *model.User) { func Authenticate(username, password, publicKey, remoteAddr, loginType string) (user *model.User, err error) {
data := map[string]string{ data := map[string]string{
"username": username, "username": username,
"password": password, "password": password,
...@@ -20,11 +20,13 @@ func Authenticate(username, password, publicKey, remoteAddr, loginType string) ( ...@@ -20,11 +20,13 @@ func Authenticate(username, password, publicKey, remoteAddr, loginType string) (
User *model.User `json:"user"` User *model.User `json:"user"`
} }
Url := client.ParseUrlQuery(UserAuthURL, nil) Url := client.ParseUrlQuery(UserAuthURL, nil)
err := client.Post(Url, data, &resp) err = client.Post(Url, data, &resp)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
return
} }
return resp.User user = resp.User
return
} }
func GetUserProfile(userId string) (user *model.User) { func GetUserProfile(userId string) (user *model.User) {
......
...@@ -3,6 +3,7 @@ package sshd ...@@ -3,6 +3,7 @@ package sshd
import ( import (
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
...@@ -37,6 +38,13 @@ func (hk *HostKey) Gen() (signer ssh.Signer, err error) { ...@@ -37,6 +38,13 @@ func (hk *HostKey) Gen() (signer ssh.Signer, err error) {
return return
} }
keyBytes := common.EncodePrivateKeyToPEM(key) keyBytes := common.EncodePrivateKeyToPEM(key)
keyDir := path.Dir(hk.Path)
if !common.FileExists(keyDir) {
err := os.MkdirAll(keyDir, os.ModePerm)
if err != nil {
return signer, err
}
}
err = common.WriteKeyToFile(keyBytes, hk.Path) err = common.WriteKeyToFile(keyBytes, hk.Path)
if err != nil { if err != nil {
return return
......
package sshd package sshd
import ( import (
"fmt"
"strconv" "strconv"
"time"
"github.com/ibuler/ssh" "github.com/ibuler/ssh"
gossh "golang.org/x/crypto/ssh"
"cocogo/pkg/auth" "cocogo/pkg/auth"
"cocogo/pkg/config" "cocogo/pkg/config"
...@@ -11,27 +14,43 @@ import ( ...@@ -11,27 +14,43 @@ import (
"cocogo/pkg/logger" "cocogo/pkg/logger"
) )
const version = "coco-v1.4" const version = "v1.4.0"
func defaultConfig(ctx ssh.Context) (conf *gossh.ServerConfig) {
conf = new(gossh.ServerConfig)
conf.NextAuthMethodsCallback = func(conn gossh.ConnMetadata) (methods []string) {
fmt.Println("Username: ", conn.User())
if conn.User() == "ibuler" {
return []string{"keyboard-interactive"}
}
return
}
return conf
}
var ( var (
conf = config.Conf conf = config.Conf
) )
func StartServer() { func StartServer() {
logger.Debug("Load host access key") logger.Debug("Load host key")
hostKey := HostKey{Value: conf.HostKey, Path: conf.HostKeyFile} hostKey := HostKey{Value: conf.HostKey, Path: conf.HostKeyFile}
signer, err := hostKey.Load() signer, err := hostKey.Load()
if err != nil { if err != nil {
logger.Fatal("Load access key error: %s", err) logger.Fatal("Load host key error: ", err)
} }
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf("Coco version %s, more see https://www.jumpserver.org\n", version)
fmt.Printf("Start ssh server at %s:%d\n", conf.BindHost, conf.SSHPort)
fmt.Println("Quit the server with CONTROL-C.")
srv := ssh.Server{ srv := ssh.Server{
Addr: conf.BindHost + ":" + strconv.Itoa(conf.SSHPort), Addr: conf.BindHost + ":" + strconv.Itoa(conf.SSHPort),
PasswordHandler: auth.CheckUserPassword, PasswordHandler: auth.CheckUserPassword,
PublicKeyHandler: auth.CheckUserPublicKey, PublicKeyHandler: auth.CheckUserPublicKey,
KeyboardInteractiveHandler: auth.CheckMFA, KeyboardInteractiveHandler: auth.CheckMFA,
DefaultServerConfigCallback: defaultConfig,
HostSigners: []ssh.Signer{signer}, HostSigners: []ssh.Signer{signer},
Version: version,
Handler: handler.SessionHandler, Handler: handler.SessionHandler,
SubsystemHandlers: map[string]ssh.SubsystemHandler{}, SubsystemHandlers: map[string]ssh.SubsystemHandler{},
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment