karelia / ConnectionKit

FTP/SFTP/WebDAV etc. for Cocoa. Join the ConnectionKit mailing list for information and suggestions.
http://lists.opensource.utr-software.com/listinfo.cgi/connection-opensource.utr-software.com
493 stars 72 forks source link

private ssh key authentication on sftp #70

Closed miralem-cebic closed 10 years ago

miralem-cebic commented 10 years ago

Hi I'm using ConnectionKit for an OSX App. The App should be a simple file uploader, because in our company there is every time a big workaround to upload stuff on server.

The authentication on server is working with private/public ssh keys. It's a SFTP Server.

To test ConnectionKit I was trying to make a connection with it.

-(void)listDirectoryAtPath:(NSString *)path
 {
 // path is here: @"download"
   NSURL *ftpServer = [NSURL URLWithString:@"sftp://companyname.eu"];
   NSURL *directory = [CK2FileManager URLWithPath:path relativeToURL:ftpServer];

   CK2FileManager *fileManager = [[CK2FileManager alloc] init];
   fileManager.delegate = self;

   [fileManager contentsOfDirectoryAtURL:directory
              includingPropertiesForKeys:nil
                                 options:NSDirectoryEnumerationSkipsHiddenFiles
                       completionHandler:^(NSArray *contents, NSError *error) {

                           if (!error) {
                               NSLog(@"%@", contents);
                           } else {
                               NSLog(@"ERROR: %@", error.localizedDescription);
                           }

                           // Display contents in your UI, or present the error if failed
                       }];
}

and the delegate looks like:

-(void)fileManager:(CK2FileManager *)manager operation:(CK2FileOperation *)operation
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(CK2AuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLCredential * C = [NSURLCredential ck2_credentialWithUser:@"<username>"
                                                     publicKeyURL:nil
                                                    privateKeyURL:[NSURL URLWithString:@"/Users/<myUserNameOnLocalMachine>/.ssh/id_rsa"]
                                                         password:nil
                                                      persistence:NSURLCredentialPersistenceForSession];
    [[challenge sender] useCredential:C forAuthenticationChallenge:challenge];
}

For me it doesn't work and I'm asking me why? Can anyone help me?

App is compiling for 64bit, OS X 10.9.1

mikeabdullah commented 10 years ago

OK, here we go:

[CK2FileManager URLWithPath:path relativeToURL:ftpServer]

Not the actual problem here, but could you try using the newer +URLWithPath:isDirectory:hostURL instead, please? I'd like to remove the older method at some point as it tends to get pretty confusing once user-entered URLs make it into the system.

[NSURL URLWithString:@"/Users/<myUserNameOnLocalMachine>/.ssh/id_rsa"]

You're passing a path here into a method that expects to receive a URL string. Suggest you want +fileURLWithPath: instead.

-(void)fileManager:(CK2FileManager *)manager operation:(CK2FileOperation *)operation didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(CK2AuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler

The first thing you ought to do in this method is test challenge.protectionSpace.authenticationMethod is NSURLAuthenticationMethodDefault. For SFTP we also issue another challenge to test if the server's public key is expected. For any protection spaces you don't want to customise the handling of, ask for the default behaviour.

[[challenge sender] useCredential:C forAuthenticationChallenge:challenge];

This approach is no longer supported; we're copying NSURLSession and you should call the completionHandler instead.

All this adds up to something like:

-(void)fileManager:(CK2FileManager *)manager operation:(CK2FileOperation *)operation
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(CK2AuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]) {
        completionHandler(CK2AuthChallengePerformDefaultHandling, nil);
        return;
    }

    NSURLCredential *cred = [NSURLCredential ck2_credentialWithUser:@"<username>"
                                                     publicKeyURL:nil
                                                    privateKeyURL:[NSURL fileURLWithPath:@"/Users/<myUserNameOnLocalMachine>/.ssh/id_rsa"]
                                                         password:nil
                                                      persistence:NSURLCredentialPersistenceForSession];
    completionHandler(CK2AuthChallengeUseCredential, cred);
}
miralem-cebic commented 10 years ago

WOW! Thanks a Lot! Its working fast and very well. Now I can do my stuff on this. Thank you very much. :)