func TestMapPublicKeyFromUserfile(t *testing.T) {
	user := "******"
	buildWorkingDir([]string{user}, t)
	defer cleanupWorkdir(t)

	privateKey, _ := ssh.ParsePrivateKey(testdata.PEMBytes["rsa"])
	publicKey := privateKey.PublicKey()
	privateKey2, _ := ssh.ParsePrivateKey(testdata.PEMBytes["dsa"])

	_ = privateKey2

	err := ioutil.WriteFile(UserKeyFile.realPath(user), testdata.PEMBytes["rsa"], 0777)
	if err != nil {
		t.Fatalf("cant create file: %v", err)
	}

	authKeys := ssh.MarshalAuthorizedKey(publicKey)
	err = ioutil.WriteFile(UserAuthorizedKeysFile.realPath(user), authKeys, 0777)
	if err != nil {
		t.Fatalf("cant create file: %v", err)
	}

	t.Logf("testing file too open")

	// UserAuthorizedKeysFile
	_, err = mapPublicKeyFromUserfile(stubConnMetadata{user}, publicKey)
	if err == nil {
		t.Fatalf("should return err when file too open")
	}

	err = os.Chmod(UserAuthorizedKeysFile.realPath(user), 0600)
	if err != nil {
		t.Fatalf("cant change file mode %v", err)
	}

	// UserKeyFile
	_, err = mapPublicKeyFromUserfile(stubConnMetadata{user}, publicKey)
	if err == nil {
		t.Fatalf("should return err when file too open")
	}

	err = os.Chmod(UserKeyFile.realPath(user), 0600)
	if err != nil {
		t.Fatalf("cant change file mode %v", err)
	}

	t.Logf("testing user not found")
	_, err = mapPublicKeyFromUserfile(stubConnMetadata{"nosuchuser"}, publicKey)
	if err == nil {
		t.Fatalf("should return err when mapping from nosuchuser")
	}

	t.Logf("testing mapping signer")
	signer, err := mapPublicKeyFromUserfile(stubConnMetadata{user}, privateKey.PublicKey())
	if err != nil {
		t.Fatalf("error mapping key %v", err)
	}

	if !bytes.Equal(signer.PublicKey().Marshal(), privateKey.PublicKey().Marshal()) {
		t.Fatalf("id_rsa not the same")
	}

	t.Logf("testing not in UserAuthorizedKeysFile")

	authKeys = ssh.MarshalAuthorizedKey(privateKey2.PublicKey())
	err = ioutil.WriteFile(UserAuthorizedKeysFile.realPath(user), authKeys, 0600)
	if err != nil {
		t.Fatalf("cant create file: %v", err)
	}

	signer, err = mapPublicKeyFromUserfile(stubConnMetadata{user}, privateKey.PublicKey())
	if signer != nil {
		t.Fatalf("should not map private key when public key not in UserAuthorizedKeysFile")
	}
}
Exemple #2
0
func main() {
	initConfig()
	initTemplate()
	initLogger()

	showVersion()
	showHelpOrVersion()

	showConfig()

	// TODO make this pluggable
	piper := &ssh.SSHPiperConfig{
		FindUpstream: findUpstreamFromUserfile,
		MapPublicKey: mapPublicKeyFromUserfile,
	}

	if config.Challenger != "" {
		ac, err := challenger.GetChallenger(config.Challenger)
		if err != nil {
			logger.Fatalln("failed to load challenger", err)
		}

		logger.Printf("using additional challenger %s", config.Challenger)
		piper.AdditionalChallenge = ac
	}

	privateBytes, err := ioutil.ReadFile(config.PiperKeyFile)
	if err != nil {
		logger.Fatalln(err)
	}

	private, err := ssh.ParsePrivateKey(privateBytes)
	if err != nil {
		logger.Fatalln(err)
	}

	piper.AddHostKey(private)

	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddr, config.Port))
	if err != nil {
		logger.Fatalln("failed to listen for connection: %v", err)
	}
	defer listener.Close()

	logger.Printf("SSHPiperd started")

	for {
		c, err := listener.Accept()
		if err != nil {
			logger.Printf("failed to accept connection: %v", err)
			continue
		}

		logger.Printf("connection accepted: %v", c.RemoteAddr())
		go func() {
			p, err := ssh.NewSSHPiperConn(c, piper)

			if err != nil {
				logger.Printf("connection from %v establishing failed reason: %v", c.RemoteAddr(), err)
				return
			}

			err = p.Wait()
			logger.Printf("connection from %v closed reason: %v", c.RemoteAddr(), err)
		}()
	}
}
Exemple #3
0
func mapPublicKeyFromUserfile(conn ssh.ConnMetadata, key ssh.PublicKey) (signer ssh.Signer, err error) {
	user := conn.User()

	if !checkUsername(user) {
		return nil, fmt.Errorf("downstream is not using a valid username")
	}

	defer func() { // print error when func exit
		if err != nil {
			logger.Printf("mapping private key error: %v, public key auth denied for [%v] from [%v]", err, user, conn.RemoteAddr())
		}
	}()

	err = UserAuthorizedKeysFile.checkPerm(user)
	if err != nil {
		return nil, err
	}

	keydata := key.Marshal()

	var rest []byte
	rest, err = UserAuthorizedKeysFile.read(user)
	if err != nil {
		return nil, err
	}

	var authedPubkey ssh.PublicKey

	for len(rest) > 0 {
		authedPubkey, _, _, rest, err = ssh.ParseAuthorizedKey(rest)

		if err != nil {
			return nil, err
		}

		if bytes.Equal(authedPubkey.Marshal(), keydata) {
			err = UserKeyFile.checkPerm(user)
			if err != nil {
				return nil, err
			}

			var privateBytes []byte
			privateBytes, err = UserKeyFile.read(user)
			if err != nil {
				return nil, err
			}

			var private ssh.Signer
			private, err = ssh.ParsePrivateKey(privateBytes)
			if err != nil {
				return nil, err
			}

			// in log may see this twice, one is for query the other is real sign again
			logger.Printf("auth succ, using mapped private key [%v] for user [%v] from [%v]", UserKeyFile.realPath(user), user, conn.RemoteAddr())
			return private, nil
		}
	}

	logger.Printf("public key auth failed user [%v] from [%v]", conn.User(), conn.RemoteAddr())

	return nil, nil
}