我尝试通过 SSL 将我的用户从我的iOS XMPP聊天客户端连接到Openfire服务器。
在我的 iOS 客户端中:
- (void)setupStream
{
...
// BOOL values for security settings
customCertEvaluation = NO;
allowSelfSignedCertificates = YES;
allowSSLHostNameMismatch = NO;
}
在我的 Openfire 服务器安全设置>中客户端连接安全性,我已设置:
Required - Clients can only connect to the server using secured connections.
因此,将调用以下委托方法:
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
NSString *expectedCertName = [xmppStream.myJID domain];
if (customCertEvaluation)
[settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
if (allowSelfSignedCertificates)
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
if (allowSSLHostNameMismatch)
[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
else
if (expectedCertName)
[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}
我从这个帖子尝试了这个解决方案:XMPPFramework TLS/SSL connection with Openfire
但是,当我运行我的应用程序并尝试连接到服务器时,我收到此错误:
Security option unavailable - kCFStreamSSLAllowsAnyRoot - You must use manual trust evaluation
我查看了GCDAsyncSocket
类,并认为kCFStreamSSLAllowsAnyRoot
被声明为已弃用。实施NSAssert是故意抛出错误。
接下来,我决定改变我的BOOL值:
- (void)setupStream
{
...
// BOOL values for security settings
// Manually evaluate trust
customCertEvaluation = YES;
allowSelfSignedCertificates = NO;
allowSSLHostNameMismatch = NO;
}
这次,再一次,无法与服务器建立连接,但没有提示错误。
如果我将客户端连接安全性更改回原始设置>我可以很好地连接到Openfire。的可选即可。但是,我不会通过SSL连接,如客户端会话中每个用户的状态旁边的 lock 图标所示。
我的Android客户端(使用Smack API for XMPP)通过SSL连接到Openfire而没有任何问题。所以我想知道我是否需要使用XMPPFramework为我的iOS客户端实现解决方法。
我非常感谢任何建议。
答案 0 :(得分:8)
在最新版本的XMPP(after April 22)中,您可以不再使用allowSelfSignedCertificates = YES
以下内容:
if (allowSelfSignedCertificates)
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];`
这是因为kCFStreamSSLAllowsAnyRoot
& SSLSetAllowsAnyRoot
已被弃用。
/*
* ==== The following UNAVAILABLE KEYS are: (with throw an exception)
* - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)
* You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).
* Corresponding deprecated method: SSLSetAllowsAnyRoot
*/
见XMPPFramework/GCDAsyncSocket.h& Deprecated Secure Transport Functions
转到Openfire服务器>安全设置>客户端连接安全性
Check: Required - Clients can only connect to the server using secured connections.
在AppDelegate中定义变量
BOOL customCertEvaluation;
在setupStream中设置变量
- (void)setupStream
{
...
customCertEvaluation = YES;
}
在willSecureWithSettings
中设置安全设置- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
/*
* Properly secure your connection by setting kCFStreamSSLPeerName
* to your server domain name
*/
[settings setObject:xmppStream.myJID.domain forKey:(NSString *)kCFStreamSSLPeerName];
/*
* Use manual trust evaluation
* as stated in the XMPPFramework/GCDAsyncSocket code documentation
*/
if (customCertEvaluation)
[settings setObject:@(YES) forKey:GCDAsyncSocketManuallyEvaluateTrust];
}
手动验证对等
/*
* This is only called if the stream is secured with settings that include:
* - GCDAsyncSocketManuallyEvaluateTrust == YES
* That is, if a delegate implements xmppStream:willSecureWithSettings:, and plugs in that key/value pair.
*/
- (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
/* Custom validation for your certificate on server should be performed */
completionHandler(YES); // After this line, SSL connection will be established
}
答案 1 :(得分:1)
在我更新了我的XMPPFramework之后,我遇到了同样的问题。经过几天试图找出问题后,我遇到了这个问题,但解决方案对我来说并不适用。
这对我有用。问题似乎源自您的 xmppStream.startTLSPolicy 。设置startTLSPolicy明确地为我工作。
xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyPreferred; // or
xmppStream.startTLSPolicy = XMPPStreamStartTLSPolicyRequired;
以下是其工作原理的说明。
在XMPPStream的handleStreamFeatures方法中,事实证明了这一点。如果您的XMPP服务器没有按需要返回起始状态'并且您没有明确设置startTLSPolicy(默认值= XMPPStreamStartTLSPolicyAllowed)。客户端只会进行正常连接,而不是TLS连接。
以下是正在进行检查的XMPPStream中的代码部分(供参考)。
/**
* This method is called anytime we receive the server's stream features.
* This method looks at the stream features, and handles any requirements so communication can continue.
**/
- (void)handleStreamFeatures
{
NSAssert(dispatch_get_specific(xmppQueueTag), @"Invoked on incorrect queue");
XMPPLogTrace();
// Extract the stream features
NSXMLElement *features = [rootElement elementForName:@"stream:features"];
// Check to see if TLS is required
// Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
NSXMLElement *f_starttls = [features elementForName:@"starttls" xmlns:@"urn:ietf:params:xml:ns:xmpp-tls"];
if (f_starttls)
{
if ([f_starttls elementForName:@"required"] || [self startTLSPolicy] >= XMPPStreamStartTLSPolicyPreferred)
{
// TLS is required for this connection
// Update state
state = STATE_XMPP_STARTTLS_1;
// Send the startTLS XML request
[self sendStartTLSRequest];
// We do not mark the stream as secure yet.
// We're waiting to receive the <proceed/> response from the
// server before we actually start the TLS handshake.
// We're already listening for the response...
return;
}
}
else if (![self isSecure] && [self startTLSPolicy] == XMPPStreamStartTLSPolicyRequired)
{
// We must abort the connection as the server doesn't support our requirements.
NSString *errMsg = @"The server does not support startTLS. And the startTLSPolicy is Required.";
NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
otherError = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];
// Close the TCP connection.
[self disconnect];
// The socketDidDisconnect:withError: method will handle everything else
return;
}
// Check to see if resource binding is required
// Don't forget about that NSXMLElement bug you reported to apple (xmlns is required or element won't be found)
NSXMLElement *f_bind = [features elementForName:@"bind" xmlns:@"urn:ietf:params:xml:ns:xmpp-bind"];
if (f_bind)
{
// Start the binding process
[self startBinding];
// We're already listening for the response...
return;
}
// It looks like all has gone well, and the connection should be ready to use now
state = STATE_XMPP_CONNECTED;
if (![self isAuthenticated])
{
[self setupKeepAliveTimer];
// Notify delegates
[multicastDelegate xmppStreamDidConnect:self];
}
}
答案 2 :(得分:0)
您正在尝试使用过时的API,请检查新版本的iPhoneXMPP示例 - https://github.com/robbiehanson/XMPPFramework/commit/73f3c35a930b91d27e62bc19e91d9cdcc02c6e42
答案 3 :(得分:0)
customCertEvaluation = YES;
allowSelfSignedCertificates = YES;
allowSSLHostNameMismatch = NO;
尝试这些可能会有所帮助