diff --git a/SOPE/GDLContentStore/GCSOpenIdFolder.m b/SOPE/GDLContentStore/GCSOpenIdFolder.m index dc6e90b64..a889a768f 100644 --- a/SOPE/GDLContentStore/GCSOpenIdFolder.m +++ b/SOPE/GDLContentStore/GCSOpenIdFolder.m @@ -303,8 +303,8 @@ static NSString *openIdFolderURLString = nil; newRecord = [NSDictionary dictionaryWithObjectsAndKeys: _user_session, @"c_user_session", _old_session, @"c_old_session", [NSNumber numberWithInt:now], @"c_session_started", - _refresh_token, @"c_refresh_token", [NSNumber numberWithInt:nowExpire] , @"c_access_token_expires_in", + _refresh_token, @"c_refresh_token", [NSNumber numberWithInt:nowRefreshExpire] , @"c_refresh_token_expires_in", nil]; record = [self recordForSession: _user_session useOldSession: NO]; diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index d661d8c2e..3740f1098 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -231,7 +231,7 @@ endif ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX) ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/ ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/ -ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef +ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef -lcurl -include GNUmakefile.preamble ifneq ($(FHS_INSTALL_ROOT),) diff --git a/SoObjects/SOGo/SOGoOpenIdSession.h b/SoObjects/SOGo/SOGoOpenIdSession.h index d24d1e93e..fd9d848bc 100644 --- a/SoObjects/SOGo/SOGoOpenIdSession.h +++ b/SoObjects/SOGo/SOGoOpenIdSession.h @@ -33,6 +33,25 @@ @class NSURL; @class NSJSONSerialization; +size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer); + +@interface SimpleOpenIdResponse: NSObject +{ + unsigned int status; + NSString *content; + NSString *headers; +} + +- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status; + +- (void)setStatus:(unsigned int)_status; +- (unsigned int)status; +- (void)setContent:(NSString *)_data; +- (NSString *)contentString; +- (void)setHearders:(NSString *)_data; +- (NSString *)headers; + +@end @interface SOGoOpenIdSession : SOGoObject { @@ -47,6 +66,7 @@ NSString *openIdClient; NSString *openIdClientSecret; NSString *openIdEmailParam; + NSString *openIdHttpVersion; BOOL openIdEnableRefreshToken; BOOL sendDomainInfo; @@ -80,12 +100,12 @@ - (void) initialize; - (void) initializeWithConfig: (NSDictionary *) _config; - (BOOL) sessionIsOK; -- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint +- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint method: (NSString *) method headers: (NSDictionary *) headers body: (NSData *) body; - (NSMutableDictionary *) fecthConfiguration: (NSString *) _domain; -- (void) setAccessToken; +- (void) setAccessToken: (NSString* ) token; - (NSString *) getRefreshToken; - (NSString *) getToken; - (NSString *) getCurrentToken; diff --git a/SoObjects/SOGo/SOGoOpenIdSession.m b/SoObjects/SOGo/SOGoOpenIdSession.m index 38710f4a1..98fc5bb81 100644 --- a/SoObjects/SOGo/SOGoOpenIdSession.m +++ b/SoObjects/SOGo/SOGoOpenIdSession.m @@ -18,8 +18,11 @@ * Boston, MA 02111-1307, USA. */ + #import +#import + #import #import #import @@ -27,12 +30,12 @@ #import - #import #import #import "NSDictionary+Utilities.h" -#import "NSString+Utilities.h" +#import +#import #import "SOGoCache.h" #import "SOGoSystemDefaults.h" @@ -40,6 +43,88 @@ static BOOL SOGoOpenIDDebugEnabled = YES; + +size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer) +{ + size_t total; + + total = size * nmemb; + [(NSMutableData *)buffer appendBytes: ptr length: total]; + + return total; +} + + +@implementation SimpleOpenIdResponse + +- (id)init { + if ((self = [super init])) { + } + return self; +} + +- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status{ + if ((self = [self init])) { + [self setStatus: _status]; + [self setContent: _data]; + [self setHeaders: _headers]; + } + return self; +} + +- (void)setStatus:(unsigned int)_status +{ + self->status = _status; +} + +- (unsigned int)status +{ + if(self->status) + return self->status; + return 0; +} + +- (void)setContent:(NSString *)_data +{ + self->content = _data; +} + +- (NSString *)contentString +{ + if(self->content) + return self->content; + return nil; +} + +- (void)setHeaders:(NSString *)_data +{ + self->headers = _data; +} + +- (NSString *)headers +{ + if(self->headers) + return self->headers; + return nil; +} + +- (NSString*)description { + NSString *co, *hd; + unsigned int st; + st = 0; + co = @"nil"; + hd = @"nil"; + if(self->status) + st = self->status; + if(self->headers) + hd = self->headers; + if(self->content) + co = self->content; + return [NSString stringWithFormat: @" , , ", st, hd, co]; +} + +@end + @implementation SOGoOpenIdSession /// Check if all required parameters to set up a OpenIdSession are in sogo.conf @@ -72,6 +157,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES; openIdClient = [_config objectForKey: @"SOGoOpenIdClient"]; openIdClientSecret = [_config objectForKey: @"SOGoOpenIdClientSecret"]; openIdEmailParam = [_config objectForKey: @"SOGoOpenIdEmailParam"]; + openIdHttpVersion = [_config objectForKey: @"SOGoOpenIdHttpVersion"]; openIdEnableRefreshToken = NO; refreshTokenBool = [_config objectForKey: @"SOGoOpenIdEnableRefreshToken"]; @@ -130,6 +216,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES; openIdClient = [sd openIdClient]; openIdClientSecret = [sd openIdClientSecret]; openIdEmailParam = [sd openIdEmailParam]; + openIdHttpVersion = [sd openIdHttpVersion]; openIdEnableRefreshToken = [sd openIdEnableRefreshToken]; userTokenInterval = [sd openIdTokenCheckInterval]; sendDomainInfo = [sd openIdSendDomainInfo]; @@ -149,66 +236,147 @@ static BOOL SOGoOpenIDDebugEnabled = YES; } } - -- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint +- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint method: (NSString *) method headers: (NSDictionary *) headers body: (NSData *) body { NSURL *url; + NSMutableData *buffer, *buffHeaders; + SimpleOpenIdResponse *response; + + CURL *curl; + struct curl_slist *headerlist=NULL; NSUInteger status; - WORequest *request; - WOResponse *response; - WOHTTPConnection *httpConnection; - - - url = [NSURL URLWithString: endpoint]; - if (url) - { - if(SOGoOpenIDDebugEnabled) - { - NSLog(@"OpenId perform request: %@ %@", method, endpoint); - NSLog(@"OpenId perform request, headers %@", headers); - // if(body) - // NSLog(@"OpenId perform request: content %@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]); - } - - httpConnection = [[WOHTTPConnection alloc] initWithURL: url]; - [httpConnection autorelease]; + NSString *content, *headerResp; + CURLcode rc; + char error[CURL_ERROR_SIZE]; - request = [[WORequest alloc] initWithMethod: method - uri: [endpoint hostlessURL] - httpVersion: @"HTTP/1.1" - headers: headers content: body - userInfo: nil]; - [request autorelease]; - [httpConnection sendRequest: request]; - response = [httpConnection readResponse]; - status = [response status]; - if(status >= 200 && status <500 && status != 404) - return response; - else if (status == 404) - { - [self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint]; - return nil; - } - else - { - [self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response]; - return nil; - } - } - else + url = [NSURL URLWithString: endpoint]; + if(!url) { [self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint]; return nil; } + + if(SOGoOpenIDDebugEnabled) + { + NSLog(@"OpenId perform request: %@ %@", method, endpoint); + NSLog(@"OpenId perform request, headers %@", headers); + } + if(SOGoOpenIDDebugEnabled) + NSLog(@"OpenId perform request, body raw %@", body); + + curl_global_init(CURL_GLOBAL_SSL); + curl = curl_easy_init(); + + if (curl) + { + error[0] = 0; + curl_easy_setopt(curl, CURLOPT_URL, [endpoint UTF8String]); + + //add form + if(body) + { + //Trick because sometimes NSData bytes don't add the \0 at the end and junk character may be added + const char *myBodyTmp = (const char*)[body bytes]; + char myBody[[body length]+1]; + strncpy(myBody, myBodyTmp, [body length]); + myBody[[body length]]='\0'; + + if(SOGoOpenIDDebugEnabled) + NSLog(@"OpenId perform request, myBodyTmp %s", myBodyTmp); + + if(SOGoOpenIDDebugEnabled) + NSLog(@"OpenId perform request, myBody %s", myBody); + + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, myBody); + } + + //add headers + if(headers) + { + NSEnumerator *enumerator = [headers keyEnumerator]; + NSString *key, *header; + while((key = [enumerator nextObject])) + { + header = [NSString stringWithFormat: @"%@: %@", key, [headers objectForKey: key]]; + headerlist = curl_slist_append(headerlist, [header UTF8String]); + } + } + if(headerlist != NULL) + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + + + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + + buffer = [NSMutableData data]; + buffHeaders = [NSMutableData data]; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_function); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_body_function); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, buffHeaders); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error); + + // Perform SOAP request + rc = curl_easy_perform(curl); + if (rc == CURLE_OK) + { + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status); + + response = [SimpleOpenIdResponse alloc]; + headerResp = [[NSString alloc] initWithData: buffHeaders + encoding: NSUTF8StringEncoding]; + + response = [response initWithResponse: nil andHeaders: headerResp andStatus: status]; + + if(status >= 200 && status <500 && status != 404) + { + content = [[NSString alloc] initWithData: buffer + encoding: NSUTF8StringEncoding]; + if (!content) + content = [[NSString alloc] initWithData: buffer + encoding: NSISOLatin1StringEncoding]; + [response setContent: content]; + + if(SOGoOpenIDDebugEnabled) + NSLog(@"OpenId perform request: response is: %@", response); + + return [response autorelease]; + } + else if (status == 404) + { + [self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint]; + return nil; + } + else + { + [self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response]; + return nil; + } + } + else + { + [self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc, + [NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]]; + } + curl_easy_cleanup (curl); + } + else + { + [self errorWithFormat: @"OpenID error when setting curl request for: %@", endpoint]; + return nil; + } } - (NSMutableDictionary *) fecthConfiguration: (NSString*) _domain { NSString *content; - WOResponse * response; + SimpleOpenIdResponse *response; + // WOResponse * response; NSUInteger status; NSMutableDictionary *result; NSDictionary *config, *headers; @@ -498,7 +666,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES; - (NSMutableDictionary *) fetchToken: (NSString * ) code redirect: (NSString *) oldLocation { NSString *location, *form, *content; - WOResponse *response; + SimpleOpenIdResponse *response; + // WOResponse *response; NSUInteger status; NSMutableDictionary *result; NSDictionary *headers; @@ -523,7 +692,10 @@ static BOOL SOGoOpenIDDebugEnabled = YES; self->forDomain, @"sogo-user-domain", nil]; else headers = [NSDictionary dictionaryWithObject: @"application/x-www-form-urlencoded" forKey: @"content-type"]; - + + if(SOGoOpenIDDebugEnabled) + NSLog(@"OpenId fetch token, form %@", form); + response = [self _performOpenIdRequest: location method: @"POST" headers: headers @@ -566,7 +738,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES; - (NSMutableDictionary *) refreshToken: (NSString * ) userRefreshToken { NSString *location, *form, *content; - WOResponse *response; + SimpleOpenIdResponse *response; + // WOResponse *response; NSUInteger status; NSMutableDictionary *result; NSDictionary *headers; @@ -639,7 +812,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES; - (NSMutableDictionary *) fetchUserInfo { NSString *location, *auth, *content; - WOResponse *response; + SimpleOpenIdResponse *response; + // WOResponse *response; NSUInteger status; NSMutableDictionary *result; NSDictionary *profile, *headers; @@ -695,7 +869,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES; } else { - [self logWithFormat: @"Error during fetching the token (status %d), response: %@", status, response]; + [self logWithFormat: @"Error fetching userInfo (status %d), response: %@", status, response]; [result setObject: @"http-error" forKey: @"error"]; } } diff --git a/SoObjects/SOGo/SOGoSystemDefaults.h b/SoObjects/SOGo/SOGoSystemDefaults.h index 3dce05cf6..fc5729ee3 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.h +++ b/SoObjects/SOGo/SOGoSystemDefaults.h @@ -106,6 +106,7 @@ NSComparisonResult languageSort(id el1, id el2, void *context); - (NSString *) openIdClient; - (NSString *) openIdClientSecret; - (NSString *) openIdEmailParam; +- (NSString *) openIdHttpVersion; - (BOOL) openIdEnableRefreshToken; - (BOOL) openIdLogoutEnabled: (NSString *) _domain; - (int) openIdTokenCheckInterval; diff --git a/SoObjects/SOGo/SOGoSystemDefaults.m b/SoObjects/SOGo/SOGoSystemDefaults.m index b47fbf6d6..a64ff76c9 100644 --- a/SoObjects/SOGo/SOGoSystemDefaults.m +++ b/SoObjects/SOGo/SOGoSystemDefaults.m @@ -779,6 +779,15 @@ NSComparisonResult languageSort(id el1, id el2, void *context) return emailParam; } +- (NSString *) openIdHttpVersion +{ + NSString *httpVersion; + httpVersion = [self stringForKey: @"SOGoOpenIdHttpVersion"]; + if(!httpVersion) + httpVersion = @"HTTP/1.1"; + return httpVersion; +} + - (BOOL) openIdLogoutEnabled: (NSString *) _domain { if(_domain && [self doesLoginTypeByDomain])