无法使用Swift中的Network Extension Framework iOS 8设置VPN连接

时间:2015-05-31 20:31:40

标签: ios swift ios8 vpn keychain

因此,当用户按下UIButton时,我一直在尝试使用iOS 8网络扩展框架来设置VPN连接。 我使用了以下教程:http://ramezanpour.net/post/2014/08/03/configure-and-manage-vpn-connections-programmatically-in-ios-8/

但由于某种原因,它不断要求输入密码和共享密码。即使我设置了passwordReference和sharedSecretReference。 如果我在安装配置文件时输入这些详细信息,它仍然无法正常工作。使用框架启动连接时,它不会做任何事情。当尝试使用设置应用程序进行连接时,它会给出一个"没有共享秘密"错误。

这是我用来设置连接的代码。

func toggleConnection(sender: UIButton) {
    if(!self.connected){
        self.manager.loadFromPreferencesWithCompletionHandler { (error) -> Void in
            if((error) != nil) {
                println("VPN Preferences error: 1")
            }
            else {
                var p = NEVPNProtocolIPSec()
                p.username = "$username"
                p.serverAddress = "$vpn"
                p.passwordReference = KeychainService.dataForKey("vpnPassword")!
                println(p.passwordReference)
                p.authenticationMethod = NEVPNIKEAuthenticationMethod.SharedSecret
                p.sharedSecretReference = KeychainService.dataForKey("sharedSecret")!
                println(p.sharedSecretReference)
                p.localIdentifier = "vpn"
                p.remoteIdentifier = "vpn"
                p.disconnectOnSleep = false


                self.manager.`protocol` = p
                self.manager.onDemandEnabled = true
                self.manager.localizedDescription = "VPN"

                self.manager.saveToPreferencesWithCompletionHandler({ (error) -> Void in
                    if((error) != nil) {
                        println("VPN Preferences error: 2")
                        println(error)
                    }
                    else {
                        var startError: NSError?
                        self.manager.connection.startVPNTunnelAndReturnError(&startError)
                        if((startError) != nil) {
                            println("VPN Preferences error: 3")
                            println(startError)
                        }
                        else {
                            println("Start VPN")
                        }
                    }
                })
            }
        }
    }
}

这些是我用作钥匙串参考的功能。

class func save(service: NSString, key: String, data: NSString) {
    var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, key, dataFromString], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData])

    SecItemDelete(keychainQuery as CFDictionaryRef)

    if data == "" { return }

    var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
    println(status)
}

class func load(service: NSString, key: String) -> NSData? {
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, key, kCFBooleanTrue, kSecMatchLimitOne, kCFBooleanTrue], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData, kSecMatchLimit, kSecReturnPersistentRef])

    var dataTypeRef :Unmanaged<AnyObject>?

    let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
    println(status)
    if (status != errSecSuccess) {
        return nil
    }

    let opaque = dataTypeRef?.toOpaque()

    var contentsOfKeychain: NSData? = nil

    if let op = opaque {
        let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
        contentsOfKeychain = retrievedData
    }
    println(contentsOfKeychain)
    return contentsOfKeychain
}

任何帮助表示赞赏!

1 个答案:

答案 0 :(得分:2)

所以我不得不用以下的Obj-C方法替换我用来访问keychain的Swift库。就目前我能说的而言,这解决了我的问题。

+ (void) storeData: (NSString * )key data:(NSData *)data {
    NSLog(@"Store Data");
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:data forKey:(__bridge id)kSecValueData];

    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
    if(errSecSuccess != status) {
        NSLog(@"Unable add item with key =%@ error:%d",key,(int)status);
    }
}

+ (NSData *) getData: (NSString *)key {
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
    [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
    [dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
    [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
    [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];

    CFTypeRef result = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);

    if( status != errSecSuccess) {
        NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
        return nil;
    }

    NSData *resultData = (__bridge NSData *)result;
    return resultData;
}