Skip to content

Commit

Permalink
Merge branch 'task/post_request_for_auth' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
ogubariev committed Sep 30, 2015
2 parents 50eea1d + a3bad0f commit 62a6b15
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 66 deletions.
5 changes: 2 additions & 3 deletions Classes/Core/JSRESTBase+JSRESTSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
@since 1.9
*/

- (BOOL)isSessionAuthorized;

- (BOOL)isSessionAuthorized __attribute__((deprecated));
- (void)verifyIsSessionAuthorizedWithCompletion:(void (^)(BOOL isSessionAuthorized))completion;

@end
135 changes: 92 additions & 43 deletions Classes/Core/JSRESTBase+JSRESTSession.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,25 @@
NSString * const kJSAuthenticationTimezoneKey = @"userTimezone";

@implementation JSRESTBase(JSRESTSession)

#pragma mark - Public API
- (BOOL)isSessionAuthorized {
return self.cookies.count > 0;
}

- (void)verifyIsSessionAuthorizedWithCompletion:(void (^)(BOOL isSessionAuthorized))completion
{
if ([self.cookies count]) {
return YES;
if (completion) {
completion(YES);
}
} else {
return [self authenticationToken];
[self authenticateWithCompletion:completion];
}
}

- (BOOL)authenticationToken
#pragma mark - Private API
- (void)fetchEncryptionKeyWithCompletion:(void(^)(NSString *modulus, NSString *exponent, NSError *error))completion
{
NSString *URI = @"GetEncryptionKey";
JSRequest *request = [[JSRequest alloc] initWithUri:URI];
Expand All @@ -58,72 +68,83 @@ - (BOOL)authenticationToken
request.method = RKRequestMethodGET;
request.responseAsObjects = NO;
request.redirectAllowed = NO;
request.asynchronous = NO;
request.asynchronous = YES;

__block BOOL authenticationSuccess = NO;
[request setCompletionBlock:@weakself(^(JSOperationResult *result)) {
NSString *password = self.serverProfile.password;

NSError *jsonError;
NSData *jsonData = result.body;
if (jsonData) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&jsonError];
if (json) {
NSString *modulus = json[@"n"];
NSString *exponent = json[@"e"];

if (modulus && exponent) {
JSEncryptionManager *encryptionManager = [JSEncryptionManager managerWithModulus:modulus
exponent:exponent];
password = [encryptionManager encryptText:password];
if (completion) {
if (result.error) {
completion(nil, nil, result.error);
} else {
NSData *jsonData = result.body;
NSError *error = nil;
if (jsonData) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&error];
if (json) {
NSString *modulus = json[@"n"];
NSString *exponent = json[@"e"];
if (modulus && exponent) {
completion(modulus, exponent, nil);
} else {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Encription Key doesn't valid. Modulus or exponent is absent."};
error = [NSError errorWithDomain:NSURLErrorDomain code:JSClientErrorCode userInfo:userInfo];
completion(nil, nil, error);
}
} else {
completion(nil, nil, error);
}
} else {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Encription Key data is empty."};
error = [NSError errorWithDomain:NSURLErrorDomain code:JSClientErrorCode userInfo:userInfo];
completion(nil, nil, error);
}
}
}
}
authenticationSuccess = [self authenticationTokenWithUsername:self.serverProfile.username
password:password
organization:self.serverProfile.organization];

} @weakselfend];
}@weakselfend];

[self sendRequest:request];
return authenticationSuccess;
}

- (BOOL)authenticationTokenWithUsername:(nonnull NSString *)username
password:(nonnull NSString *)password
organization:(nullable NSString *)organization
- (void)fetchAuthenticationTokenWithUsername:(NSString *)username
password:(NSString *)password
organization:(NSString *)organization
method:(RKRequestMethod)requestMethod
completion:(void(^)(BOOL isTokenFetchedSuccessful))completion
{
JSRequest *request = [[JSRequest alloc] initWithUri:[JSConstants sharedInstance].REST_AUTHENTICATION_URI];
request.restVersion = JSRESTVersion_None;
request.method = RKRequestMethodGET;
request.method = requestMethod;
request.responseAsObjects = NO;
request.redirectAllowed = NO;
request.asynchronous = NO;
request.asynchronous = YES;

[self resetReachabilityStatus];

[request addParameter:kJSAuthenticationUsernameKey withStringValue:username];
[request addParameter:kJSAuthenticationPasswordKey withStringValue:password];
[request addParameter:kJSAuthenticationOrganizationKey withStringValue:organization];
[request addParameter:kJSAuthenticationTimezoneKey withStringValue:[[NSTimeZone localTimeZone] name]];

// Add locale to session
NSString *currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
NSInteger dividerPosition = [currentLanguage rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"_-"]].location;
if (dividerPosition != NSNotFound) {
currentLanguage = [currentLanguage substringToIndex:dividerPosition];
}
NSString *currentLocale = [[JSConstants sharedInstance].REST_JRS_LOCALE_SUPPORTED objectForKey:currentLanguage];

[request addParameter:kJSAuthenticationUsernameKey withStringValue:username];
[request addParameter:kJSAuthenticationPasswordKey withStringValue:password];
[request addParameter:kJSAuthenticationOrganizationKey withStringValue:organization];
[request addParameter:kJSAuthenticationTimezoneKey withStringValue:[[NSTimeZone localTimeZone] name]];
[request addParameter:kJSAuthenticationLocaleKey withStringValue:currentLocale];

__block BOOL authenticationSuccess = NO;
if (requestMethod == RKRequestMethodPOST) {
self.restKitObjectManager.requestSerializationMIMEType = RKMIMETypeFormURLEncoded;
}

[request setCompletionBlock:@weakself(^(JSOperationResult *result)) {
BOOL isTokenFetchedSuccessful = NO;
switch (result.statusCode) {
case 401: // Unauthorized
case 403: { // Forbidden
authenticationSuccess = NO;
isTokenFetchedSuccessful = NO;
break;
}
case 302: { // redirect
Expand All @@ -134,17 +155,45 @@ - (BOOL)authenticationTokenWithUsername:(nonnull NSString *)username
NSRange errorStringRange = [location rangeOfString:@"error"];
isErrorRedirect = errorStringRange.length > 0;
}
authenticationSuccess = !result.error && !isErrorRedirect;
isTokenFetchedSuccessful = !result.error && !isErrorRedirect;
break;
}
default: {
authenticationSuccess = (!result.error);
isTokenFetchedSuccessful = (!result.error);
}
}
if (completion) {
completion(isTokenFetchedSuccessful);
}
} @weakselfend];
[self sendRequest:request];
}

- (void)authenticateWithCompletion:(void(^)(BOOL isSuccess))completion
{
NSString *username = self.serverProfile.username;
NSString *password = self.serverProfile.password;
NSString *organization = self.serverProfile.organization;

[self fetchEncryptionKeyWithCompletion:@weakself(^(NSString *modulus, NSString *exponent, NSError *error)) {
NSString *encPassword = password;
if (modulus && exponent) {
JSEncryptionManager *encryptionManager = [JSEncryptionManager managerWithModulus:modulus
exponent:exponent];
encPassword = [encryptionManager encryptText:password];
}

return authenticationSuccess;
[self fetchAuthenticationTokenWithUsername:username
password:encPassword
organization:organization
method:RKRequestMethodPOST // TODO: make select method
completion:@weakself(^(BOOL isTokenFetchedSuccessful)) {
self.restKitObjectManager.requestSerializationMIMEType = RKMIMETypeJSON;
if (completion) {
completion(isTokenFetchedSuccessful);
}
}@weakselfend];
}@weakselfend];
}

@end
18 changes: 15 additions & 3 deletions Classes/Core/JSRESTBase.m
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,21 @@ - (void)sendRequest:(nonnull JSRequest *)jsRequest additionalHTTPHeaderFields:(n
if (descriptiorHolder && [[descriptiorHolder class] respondsToSelector:@selector(rkRequestDescriptorsForServerProfile:)]) {
[self.restKitObjectManager addRequestDescriptorsFromArray:[[descriptiorHolder class] rkRequestDescriptorsForServerProfile:self.serverProfile]];
}

NSMutableURLRequest *urlRequest = [self.restKitObjectManager requestWithObject:jsRequest.body method:jsRequest.method path:fullUri parameters:jsRequest.params];


NSMutableURLRequest *urlRequest;
if (jsRequest.multipartFormConstructingBodyBlock) {
urlRequest = [self.restKitObjectManager multipartFormRequestWithObject:self
method:jsRequest.method
path:fullUri
parameters:nil
constructingBodyWithBlock:jsRequest.multipartFormConstructingBodyBlock];
} else {
urlRequest = [self.restKitObjectManager requestWithObject:jsRequest.body
method:jsRequest.method
path:fullUri
parameters:jsRequest.params];
}

RKHTTPRequestOperation *httpOperation = [[RKHTTPRequestOperation alloc] initWithRequest:urlRequest];
NSOperation *requestOperation = httpOperation;

Expand Down
6 changes: 6 additions & 0 deletions Classes/Core/JSRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ typedef enum {
*/
@property (nonatomic, assign) BOOL redirectAllowed;

/**
Allow construct mulpipart body
@since 2.1.2
*/
@property (nonatomic, copy) void(^multipartFormConstructingBodyBlock)(id <AFMultipartFormData> formData);

/**
Returns a request instance with predefined uri.
Expand Down
18 changes: 7 additions & 11 deletions Classes/Helpers/JSEncryptionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ - (NSString *)encryptText:(NSString *)text
{
NSData *publicKeyData = [self generatePublicKeyDataFromModulus:self.modulus exponent:self.exponent];
SecKeyRef publicKeyRef = [self addPublicKeyWithTagName:kJSAuthenticationTag keyBits:publicKeyData];
// There is issue with iOS9 when SecItemCopyMatching() - works wrong.

// There is an issue with iOS9 when SecItemCopyMatching() - works wrong.
if (!publicKeyRef) {
return text;
}
Expand Down Expand Up @@ -92,7 +93,6 @@ - (NSData *)generatePublicKeyDataFromModulus:(NSString *)modulus exponent:(NSStr

- (SecKeyRef)addPublicKeyWithTagName:(NSString *)tagName keyBits:(NSData *)publicKey
{
OSStatus sanityCheck = 0;
SecKeyRef peerKeyRef = NULL;
CFTypeRef persistPeer = NULL;

Expand All @@ -105,13 +105,11 @@ - (SecKeyRef)addPublicKeyWithTagName:(NSString *)tagName keyBits:(NSData *)publi
peerPublicKeyAttr[(__bridge id) kSecAttrApplicationTag] = peerTag;
peerPublicKeyAttr[(__bridge id) kSecReturnPersistentRef] = @(YES);

sanityCheck = SecItemDelete((__bridge_retained CFDictionaryRef)peerPublicKeyAttr);
// NSLog(@"delete item status: %ld", sanityCheck);
SecItemDelete((__bridge CFDictionaryRef)peerPublicKeyAttr);

peerPublicKeyAttr[(__bridge id) kSecValueData] = publicKey;

sanityCheck = SecItemAdd((__bridge_retained CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer);
// NSLog(@"add item status: %ld", sanityCheck);
SecItemAdd((__bridge CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer);

if (persistPeer) {
NSMutableDictionary* query = [
Expand All @@ -120,14 +118,12 @@ - (SecKeyRef)addPublicKeyWithTagName:(NSString *)tagName keyBits:(NSData *)publi
(__bridge id) kSecReturnRef : @YES
} mutableCopy];

sanityCheck = SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, (CFTypeRef*)&peerKeyRef);
// NSLog(@"copy matching from persistent ref status: %ld", sanityCheck);
SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&peerKeyRef);
} else {
[peerPublicKeyAttr removeObjectForKey:(__bridge id)kSecValueData];
peerPublicKeyAttr[(__bridge id) kSecReturnRef] = @YES;
// Let's retry a different way.
sanityCheck = SecItemCopyMatching((__bridge_retained CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&peerKeyRef);
// NSLog(@"copy matching from tag status: %ld", sanityCheck);
SecItemCopyMatching((__bridge CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&peerKeyRef);
}

if (persistPeer) CFRelease(persistPeer);
Expand All @@ -146,6 +142,7 @@ - (NSData *)encryptText:(NSString *)plainTextString withKey:(SecKeyRef)publicKey
&cipherBuffer[0],
&cipherBufferSize);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
free(cipherBuffer);
return encryptedData;
}

Expand All @@ -172,7 +169,6 @@ - (NSData *)dataFromString:(NSString *)string
whole_byte = (unsigned char) strtol(byte_chars, NULL, 16);
[result appendBytes:&whole_byte length:1];
}
NSLog(@"%@", result);

return result;
}
Expand Down
9 changes: 3 additions & 6 deletions Classes/Helpers/KeychainItemWrapper/KeychainItemWrapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,9 @@ - (id)objectForKey:(id)key
- (void)resetKeychainItem
{
OSStatus junk = noErr;
if (!keychainItemData)
{
self.keychainItemData = [[NSMutableDictionary alloc] init];
}
else if (keychainItemData)
{
if (!keychainItemData) {
keychainItemData = [[NSMutableDictionary alloc] init];
} else {
NSMutableDictionary *tempDictionary = [self dictionaryToSecItemFormat:keychainItemData];
junk = SecItemDelete((CFDictionaryRef)tempDictionary);
NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." );
Expand Down

0 comments on commit 62a6b15

Please sign in to comment.