NSTask和Git -- 权限问题

9
在我的Cocoa应用程序中,我正在尝试使用NSTask运行一些基本的Git命令。每当我运行需要权限(SSH密钥)访问远程的命令(例如git push, git pull)时,它都会失败并显示以下错误:

Permission denied (publickey). The remote end hung up unexpectedly

从终端运行相同的命令完全正常,因此我认为这可能是NSTask未设置环境变量的问题,在访问ssh密钥的过程中会使用该变量。我尝试手动设置HOMEUSER环境变量,如下所示:

[task setEnvironment:[NSDictionary dictionaryWithObjectsAndKeys:NSHomeDirectory(), @"HOME", NSUserName(), @"USER", nil]];

但是这没有任何效果。我需要在NSTask中设置特定的环境变量才能使其正常工作吗?
编辑:感谢Dustin的提示,我在解决这个问题时有了一些进展。我使用env命令列出了当前会话的环境变量,并找到了这个:
SSH_AUTH_SOCK=/tmp/launch-DMQopt/Listeners

为了测试,我复制了这个路径并将其设置为NSTask的环境变量,并再次运行代码,这次它成功了!话虽如此,我确定SSH_AUTH_SOCK每个会话都会改变,所以我不能硬编码它。那么我该如何动态生成/检索这个变量呢?


1
尝试另一种方式,使用命令行上的 env -i,看看需要添加多少内容才能使其正常工作。 - Dustin
因为你的提示,我又进展了一点,详见我的编辑后的帖子 :) - indragie
1个回答

4
你可以尝试按照教程“在NSTask中包装rsync或SSH”(来自Ira),其中提到了SSH_AUTH_SOCK变量:

撰写本文后,我意识到在设置NSTask的环境变量时漏掉了一个重要的步骤。
为了使无密码基于密钥的认证工作,需要从用户的环境中获取SSH_AUTH_SOCK变量并将其包含在NSTask的环境中。
因此,在设置环境变量时,例如;

NSTask *task;
NSDictionary *environmentDict = [[NSProcessInfo processInfo] environment];
// Environment variables needed for password based authentication 
NSMutableDictionary *env = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                         @"NONE", @"DISPLAY",                           askPassPath, @"SSH_ASKPASS",
                         userName,@"AUTH_USERNAME",
                         hostName,@"AUTH_HOSTNAME",
                         nil];

// Environment variable needed for key based authentication
[env setObject:[environmentDict objectForKey:@"SSH_AUTH_SOCK"] forKey:@"SSH_AUTH_SOCK"];

// Setting the task's environment
[task setEnvironment:env];

然而,OP indragie 评论道:

我之前尝试过这个方法,但由于它是在XCode中调用的,SSH_AUTH_SOCK 环境变量没有被传递给它。
从Finder中打开应用程序可以解决这个问题。



使用askPassPath作为Askpass可执行文件的路径,它包含在应用程序的主捆绑包中。(为了做到这一点,请在xcode中的“产品”下找到可执行文件,然后将其拖到主应用程序目标的“复制捆绑资源”中。)
// Get the path of the Askpass program, which is
// setup to be included as part of the main application bundle
NSString *askPassPath = [NSBundle pathForResource:@"Askpass"
              ofType:@"" 
              inDirectory:[[NSBundle mainBundle] bundlePath]];

1
我之前尝试过这个,但由于它是通过Xcode调用的,SSH_AUTH_SOCK环境变量没有被传递给它。从Finder打开应用程序可以解决这个问题。谢谢! - indragie
@indragie:非常好。我已经将您的评论包含在答案中以增加可见性。 - VonC
@VonC,你能告诉我askPassPath变量是什么吗? - Just a coder
@user76859403 好的,我已经恢复了链接,并在编辑后的答案中包含了 askPassPath - VonC
@VonC 好的...看起来这应该是我的问题。我在使用带有 NSTask 的 MaC OS Xcode --> ssh_askpass:exec(/usr/libexec/ssh-askpass):没有这样的文件或目录。 主机密钥验证失败。我想我必须找到另一个解决方案(在我的系统上找不到该文件,但它仍在寻找)。我之前尝试进行 GIT 克隆操作。你所做的代码编辑对我也无效。 - Just a coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接