PNXMPPFramework/Authentication/Deprecated-Plain/XMPPDeprecatedPlainAuthentication.m
2016-02-24 16:56:39 +01:00

157 lines
4.0 KiB
Objective-C

#import "XMPPDeprecatedPlainAuthentication.h"
#import "XMPP.h"
#import "XMPPInternal.h"
#import "XMPPLogging.h"
#import "NSXMLElement+XMPP.h"
#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif
// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif
@implementation XMPPDeprecatedPlainAuthentication
{
#if __has_feature(objc_arc_weak)
__weak XMPPStream *xmppStream;
#else
__unsafe_unretained XMPPStream *xmppStream;
#endif
NSString *password;
}
+ (NSString *)mechanismName
{
// This deprecated method isn't listed in the normal mechanisms list
return nil;
}
- (id)initWithStream:(XMPPStream *)stream password:(NSString *)inPassword
{
if ((self = [super init]))
{
xmppStream = stream;
password = inPassword;
}
return self;
}
- (BOOL)start:(NSError **)errPtr
{
XMPPLogTrace();
// The server does not appear to support SASL authentication (at least any type we can use)
// So we'll revert back to the old fashioned jabber:iq:auth mechanism
XMPPJID *myJID = xmppStream.myJID;
NSString *username = [myJID user];
NSString *resource = [myJID resource];
if ([resource length] == 0)
{
// If resource is nil or empty, we need to auto-create one
resource = [XMPPStream generateUUID];
}
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:auth"];
[query addChild:[NSXMLElement elementWithName:@"username" stringValue:username]];
[query addChild:[NSXMLElement elementWithName:@"resource" stringValue:resource]];
[query addChild:[NSXMLElement elementWithName:@"password" stringValue:password]];
XMPPIQ *iq = [XMPPIQ iqWithType:@"set"];
[iq addChild:query];
[xmppStream sendAuthElement:iq];
return YES;
}
- (XMPPHandleAuthResponse)handleAuth:(NSXMLElement *)authResponse
{
XMPPLogTrace();
// We used the old fashioned jabber:iq:auth mechanism
if ([[authResponse attributeStringValueForName:@"type"] isEqualToString:@"error"])
{
return XMPP_AUTH_FAIL;
}
else
{
return XMPP_AUTH_SUCCESS;
}
}
- (BOOL)shouldResendOpeningNegotiationAfterSuccessfulAuthentication
{
return NO;
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation XMPPStream (XMPPDeprecatedPlainAuthentication)
/**
* This method only applies to servers that don't support XMPP version 1.0, as defined in RFC 3920.
* With these servers, we attempt to discover supported authentication modes via the jabber:iq:auth namespace.
**/
- (BOOL)supportsDeprecatedPlainAuthentication
{
__block BOOL result = NO;
dispatch_block_t block = ^{ @autoreleasepool {
// The root element can be properly queried for authentication mechanisms anytime after the
// stream:features are received, and TLS has been setup (if required)
if (self.state >= STATE_XMPP_POST_NEGOTIATION)
{
// Search for an iq element within the rootElement.
// Recall that some servers might stupidly add a "jabber:client" namespace which might cause problems
// if we simply used the elementForName method.
NSXMLElement *iq = nil;
NSUInteger i, count = [self.rootElement childCount];
for (i = 0; i < count; i++)
{
NSXMLNode *childNode = [self.rootElement childAtIndex:i];
if ([childNode kind] == NSXMLElementKind)
{
if ([[childNode name] isEqualToString:@"iq"])
{
iq = (NSXMLElement *)childNode;
}
}
}
NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:auth"];
NSXMLElement *plain = [query elementForName:@"password"];
result = (plain != nil);
}
}};
if (dispatch_get_specific(self.xmppQueueTag))
block();
else
dispatch_sync(self.xmppQueue, block);
return result;
}
@end