Esempio n. 1
0
func (suite *ServerSuite) createConfig() Config {

	// Create logger
	writer := log.NewConcurrentWriter(os.Stdout)
	// writer := log.NewConcurrentWriter(ioutil.Discard)
	logger := log.NewLogger(writer, "sshh")
	// logger := log.DefaultLog

	// Get signer
	signer, err := ssh.ParsePrivateKey([]byte(serverKey))
	if err != nil {
		suite.Fail("Private key could not be parsed", err.Error())
	}

	// Create config
	cfg := Config{
		Deadline: time.Second,
		Handlers: map[string]SSHHandler{
			"echo": &EchoHandler{log.New("echo")},
			"bad":  &BadHandler{},
		},
		Logger:            logger,
		Bind:              ":9022",
		PrivateKey:        signer,
		PasswordCallback:  passwordCallback,
		PublicKeyCallback: publicKeyCallback,
	}
	return cfg
}
Esempio n. 2
0
func (suite *ServerSuite) TestWildcard() {

	writer := log.NewConcurrentWriter(os.Stdout)
	logger := log.NewLogger(writer, "sshh_test")

	r := router.New(logger, nil, nil)
	r.Register("/echo", &EchoHandler{log.New("echo")})
	r.Register("/bad", &BadHandler{})

	acceptErr := errors.New("accept error")
	ch := &sshmocks.MockNewChannel{
		TypeName:  "*",
		AcceptErr: acceptErr,
	}
	ch.On("ChannelType").Return("*")
	ch.On("Reject", ssh.UnknownChannelType, "*").Return(errors.New("unknown reason 1000"))

	conn := &sshmocks.MockConn{}
	conn.On("Close").Return(nil)
	serverConn := ssh.ServerConn{
		Conn: conn,
	}
	// Create dispatcher
	dispatcher := &UrlDispatcher{Logger: log.NullLog, Router: r}
	dispatcher.Dispatch(context.Background(), &serverConn, ch)

	// assert that the expectations were met
	ch.AssertCalled(suite.T(), "ChannelType")
	ch.AssertCalled(suite.T(), "Reject", ssh.UnknownChannelType, "*")
	conn.AssertCalled(suite.T(), "Close")
}
Esempio n. 3
0
func TestConfig(t *testing.T) {
	var authLogCalled bool
	var authLogCallback = func(conn ssh.ConnMetadata, method string, err error) {
		authLogCalled = true
	}

	// Create logger
	writer := log.NewConcurrentWriter(ioutil.Discard)
	logger := log.NewLogger(writer, "sshh")

	// Get signer
	signer, err := ssh.ParsePrivateKey([]byte(serverKey))
	if err != nil {
		t.Fatalf("Private key could not be parsed", err.Error())
	}

	r := router.New(logger, nil, nil)
	r.Register("/echo", &EchoHandler{log.New("echo")})

	cfg := Config{
		Deadline: time.Second,
		Dispatcher: &UrlDispatcher{
			Router: r,
			Logger: logger,
		},
		// Handlers: map[string]SSHHandler{
		// 	"echo": &EchoHandler{log.New("echo")},
		// },
		Logger:            logger,
		Bind:              ":9022",
		PrivateKey:        signer,
		AuthLogCallback:   authLogCallback,
		PasswordCallback:  passwordCallback,
		PublicKeyCallback: publicKeyCallback,
	}

	// Assertions
	assert.Equal(t, time.Second, cfg.Deadline, "Deadline should be 1s")
	assert.Equal(t, ":9022", cfg.Bind, "Bind should be :9022")

	// Create SSH config
	c := cfg.SSHConfig()
	assert.NotNil(t, c, "SSH config should not be nil")
	assert.Equal(t, passwordCallback, c.PasswordCallback, "PasswordCallback should use the one we passed in")
	assert.Equal(t, publicKeyCallback, c.PublicKeyCallback, "PublicKeyCallback should use the one we passed in")
	assert.Equal(t, authLogCallback, c.AuthLogCallback, "AuthLogCallback should use the one we passed in")

	// // Test Handlers
	// h, ok := cfg.Handler("echo")
	// assert.True(t, ok, "Echo handler should be registered")
	// assert.NotNil(t, h, "Echo handler should not be nil")

	// h, ok = cfg.Handler("shell")
	// assert.False(t, ok, "Shell handler should not be registered")
	// assert.Nil(t, h, "Shell handler should be nil")
}
Esempio n. 4
0
func (suite *ServerSuite) createConfig() Config {

	// Create logger
	writer := log.NewConcurrentWriter(os.Stdout)
	// writer := log.NewConcurrentWriter(ioutil.Discard)
	logger := log.NewLogger(writer, "sshh")
	// logger := log.DefaultLog

	// Get signer
	signer, err := ssh.ParsePrivateKey([]byte(serverKey))
	if err != nil {
		suite.Fail("Private key could not be parsed", err.Error())
	}

	r := router.New(logger, nil, nil)
	r.Register("/echo", &EchoHandler{log.New("echo")})
	r.Register("/bad", &BadHandler{})

	// Create config
	cfg := Config{
		Context:  context.Background(),
		Deadline: time.Second,
		Dispatcher: &UrlDispatcher{
			Router: r,
			Logger: logger,
		},
		// Handlers: map[string]SSHHandler{
		// 	"echo": &EchoHandler{log.New("echo")},
		// 	"bad":  &BadHandler{},
		// },
		Logger:            logger,
		Bind:              ":9022",
		PrivateKey:        signer,
		PasswordCallback:  passwordCallback,
		PublicKeyCallback: publicKeyCallback,
	}
	return cfg
}
Esempio n. 5
0
	"github.com/blacklabeldata/kappa/skl"
	"github.com/blacklabeldata/xbinary"
	"golang.org/x/crypto/ssh"
	// "golang.org/x/crypto/ssh/terminal"
	"github.com/subsilent/crypto/ssh/terminal"
)

// ClientCmd is the CLI command
var ClientCmd = &cobra.Command{
	Use:   "client [ssh://username@host:port]",
	Short: "client starts a terminal with the given kappa server",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {

		// Create logger
		writer := log.NewConcurrentWriter(os.Stdout)
		logger := log.NewLogger(writer, "cli")

		err := InitializeClientConfig(logger)
		if err != nil {
			return
		}

		// Get SSH Key file
		keyFile := viper.GetString("ClientKey")
		// logger.Info("Reading private key", "file", sshKeyFile)

		// Read SSH Key
		keyBytes, err := ioutil.ReadFile(keyFile)
		if err != nil {
			fmt.Println("Private key could not be read:", err.Error())
Esempio n. 6
0
func New(c *Config) (cer Cerebrum, err error) {

	// Create logger
	if c.LogOutput == nil {
		c.LogOutput = log.NewConcurrentWriter(os.Stderr)
	}
	logger := log.NewLogger(c.LogOutput, "kappa")

	// Create data directory
	if err = os.MkdirAll(c.DataPath, 0755); err != nil {
		logger.Warn("Could not create data directory", "err", err)
		return
	}

	// Setup reconciler
	serfEventCh := make(chan serf.Event, 256)
	reconcilerCh := make(chan serf.Member, 32)

	ctx, cancel := context.WithCancel(context.Background())
	cereb := &cerebrum{
		config:      c,
		logger:      logger,
		dialer:      NewDialer(NewPool(c.LogOutput, 5*time.Minute, c.TLSConfig)),
		serfEventCh: serfEventCh,
		reconcileCh: reconcilerCh,
		grim:        grim.ReaperWithContext(ctx),
		context:     ctx,
		cancel:      cancel,
	}

	// Create serf server
	err = cereb.setupRaft()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return nil, err
	}

	isLeader := func() bool { return cereb.raft.State() == raft.Leader }
	reconciler := &Reconciler{reconcilerCh, isLeader}
	cereb.serfer = serfer.NewSerfer(serfEventCh, serfer.SerfEventHandler{
		Logger:              log.NewLogger(c.LogOutput, CerebrumEventPrefix),
		ServicePrefix:       CerebrumEventPrefix,
		ReconcileOnJoin:     true,
		ReconcileOnLeave:    true,
		ReconcileOnFail:     true,
		ReconcileOnUpdate:   true,
		ReconcileOnReap:     true,
		NodeJoined:          c.NodeJoined,
		NodeUpdated:         c.NodeUpdated,
		NodeLeft:            c.NodeLeft,
		NodeFailed:          c.NodeFailed,
		NodeReaped:          c.NodeReaped,
		UserEvent:           c.UserEvent,
		UnknownEventHandler: c.UnknownEventHandler,
		Reconciler:          reconciler,
		IsLeader:            isLeader,
		IsLeaderEvent: func(name string) bool {
			return name == CerebrumLeaderEvent
		},
		LeaderElectionHandler: cereb,
	})

	// Create serf server
	cereb.serf, err = cereb.setupSerf()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return nil, err
	}

	cer = cereb
	return cer, nil
}
Esempio n. 7
0
func main() {

	// Create logger
	writer := log.NewConcurrentWriter(os.Stdout)
	logger := log.NewLogger(writer, "sshh")

	// Get private key
	privateKey, err := ssh.ParsePrivateKey([]byte(privateKey))
	if err != nil {
		logger.Warn("Private key could not be parsed", "error", err.Error())
	}

	// Setup server config
	config := sshh.Config{
		Deadline: time.Second,
		Logger:   logger,
		Bind:     ":9022",
		Handlers: map[string]sshh.SSHHandler{
			"session": NewShellHandler(logger),
		},
		PrivateKey: privateKey,
		PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (perm *ssh.Permissions, err error) {
			if conn.User() == "admin" && string(password) == "password" {

				// Add username to permissions
				perm = &ssh.Permissions{
					Extensions: map[string]string{
						"username": conn.User(),
					},
				}
			} else {
				err = fmt.Errorf("Invalid username or password")
			}
			return
		},
		AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) {
			if err == nil {
				logger.Info("Successful login", "user", conn.User(), "method", method)
			}
		},
		// PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (perm *ssh.Permissions, err error) {
		// 	return nil, fmt.Errorf("Unauthorized")
		// },
	}

	// Create SSH server
	sshServer, err := sshh.NewSSHServer(&config)
	if err != nil {
		logger.Error("SSH Server could not be configured", "error", err.Error())
		return
	}

	// Start servers
	sshServer.Start()

	// Handle signals
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, os.Kill)

	// Wait for signal
	logger.Info("Ready to serve requests")

	// Block until signal is received
	<-sig

	// Stop listening for signals and close channel
	signal.Stop(sig)
	close(sig)

	// Shut down SSH server
	logger.Info("Shutting down servers.")
	sshServer.Stop()
}
Esempio n. 8
0
func NewServer(c *DatabaseConfig) (server *Server, err error) {

	// Create logger
	if c.LogOutput == nil {
		c.LogOutput = log.NewConcurrentWriter(os.Stdout)
	}
	logger := log.NewLogger(c.LogOutput, "kappa")

	// Create data directory
	if err = os.MkdirAll(c.DataPath, 0755); err != nil {
		logger.Warn("Could not create data directory", "err", err)
		// logger.Warn("Could not create data directory", "err", err.Error())
		return
	}

	// Connect to database
	cwd, err := os.Getwd()
	if err != nil {
		logger.Error("Could not get working directory", "error", err.Error())
		return
	}

	file := path.Join(cwd, c.DataPath, "meta.db")
	logger.Info("Connecting to database", "file", file)
	system, err := datamodel.NewSystem(file)
	if err != nil {
		logger.Error("Could not connect to database", "error", err.Error())
		return
	}

	// Get SSH Key file
	sshKeyFile := c.SSHPrivateKeyFile
	logger.Info("Reading private key", "file", sshKeyFile)

	privateKey, err := auth.ReadPrivateKey(logger, sshKeyFile)
	if err != nil {
		return
	}

	// Get admin certificate
	adminCertFile := c.AdminCertificateFile
	logger.Info("Reading admin public key", "file", adminCertFile)

	// Read admin certificate
	cert, err := ioutil.ReadFile(adminCertFile)
	if err != nil {
		logger.Error("admin certificate could not be read", "filename", c.AdminCertificateFile)
		return
	}

	// Add admin cert to key ring
	userStore, err := system.Users()
	if err != nil {
		logger.Error("could not get user store", "error", err.Error())
		return
	}

	// Create admin account
	admin, err := userStore.Create("admin")
	if err != nil {
		logger.Error("error creating admin account", "error", err.Error())
		return
	}

	// Add admin certificate
	keyRing := admin.KeyRing()
	fingerprint, err := keyRing.AddPublicKey(cert)
	if err != nil {
		logger.Error("admin certificate could not be added", "error", err.Error())
		return
	}
	logger.Info("Added admin certificate", "fingerprint", fingerprint)

	// Read root cert
	rootPem, err := ioutil.ReadFile(c.CACertificateFile)
	if err != nil {
		logger.Error("root certificate could not be read", "filename", c.CACertificateFile)
		return
	}

	// Create certificate pool
	roots := x509.NewCertPool()
	if ok := roots.AppendCertsFromPEM(rootPem); !ok {
		logger.Error("failed to parse root certificate")
		return
	}

	// Setup SSH Server
	sshLogger := log.NewLogger(c.LogOutput, "ssh")
	pubKeyCallback, err := PublicKeyCallback(system)
	if err != nil {
		logger.Error("failed to create PublicKeyCallback", err)
		return
	}

	// Setup server config
	config := sshh.Config{
		Deadline:          c.SSHConnectionDeadline,
		Logger:            sshLogger,
		Bind:              c.SSHBindAddress,
		PrivateKey:        privateKey,
		PublicKeyCallback: pubKeyCallback,
		AuthLogCallback: func(meta ssh.ConnMetadata, method string, err error) {
			if err == nil {
				sshLogger.Info("login success", "user", meta.User())
			} else if err != nil && method == "publickey" {
				sshLogger.Info("login failure", "user", meta.User(), "err", err.Error())
			}
		},
		Handlers: map[string]sshh.SSHHandler{
			"kappa-client": &EchoHandler{},
		},
	}

	// Create SSH server
	sshServer, err := sshh.NewSSHServer(&config)
	if err != nil {
		logger.Error("SSH Server could not be configured", "error", err.Error())
		return
	}

	// Setup Serf handlers
	mgr := NewNodeList()
	reconcilerCh := make(chan serf.Member, 32)
	serfEventCh := make(chan serf.Event, 256)
	userEventCh := make(chan serf.UserEvent, 256)
	serfer := serfer.NewSerfer(serfEventCh, serfer.SerfEventHandler{
		Logger:            log.NewLogger(c.LogOutput, "serf"),
		ServicePrefix:     "kappa",
		ReconcileOnJoin:   true,
		ReconcileOnLeave:  true,
		ReconcileOnFail:   true,
		ReconcileOnUpdate: true,
		ReconcileOnReap:   true,
		NodeJoined: &SerfNodeJoinHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-join")},
		NodeUpdated: &SerfNodeUpdateHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-update")},
		NodeLeft: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-left")},
		NodeFailed: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-fail")},
		NodeReaped: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-reap")},
		UserEvent: &SerfUserEventHandler{
			log.NewLogger(c.LogOutput, "serf:user-events"), userEventCh},
		UnknownEventHandler: &SerfUserEventHandler{
			log.NewLogger(c.LogOutput, "serf:unknown-event"), userEventCh},
		Reconciler: &SerfReconciler{reconcilerCh},
		IsLeader: func() bool {

			// TODO: Replace with Raft IsLeader check
			return true
		},
	})

	// Create database server
	s := &Server{
		config:       c,
		logger:       logger,
		sshServer:    &sshServer,
		serfer:       serfer,
		localKappas:  make(map[string]*NodeDetails),
		serfEventCh:  serfEventCh,
		kappaEventCh: userEventCh,
		reconcileCh:  reconcilerCh,
	}

	// Create serf server
	s.serf, err = s.setupSerf()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return
	}

	return s, nil
}