From cd294603dfd5a25cf383ea7237f9d6d078db3ef7 Mon Sep 17 00:00:00 2001 From: Hivert Quentin Date: Mon, 26 May 2025 17:40:14 +0200 Subject: [PATCH] feat(openid): change WORequest to curl lib --- SoObjects/SOGo/GNUmakefile | 2 +- SoObjects/SOGo/SOGoOpenIdSession.h | 19 +- SoObjects/SOGo/SOGoOpenIdSession.m | 269 +++++++++++++++++++++++----- SoObjects/SOGo/SOGoSystemDefaults.h | 1 + SoObjects/SOGo/SOGoSystemDefaults.m | 9 + 5 files changed, 251 insertions(+), 49 deletions(-) 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..34e68fa20 100644 --- a/SoObjects/SOGo/SOGoOpenIdSession.h +++ b/SoObjects/SOGo/SOGoOpenIdSession.h @@ -33,6 +33,22 @@ @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; +} + +- (id)initWithResponse: (NSString *)_data andStatus:(unsigned int )_status; + +- (void)setStatus:(unsigned int)_status; +- (unsigned int)status; +- (void)setContent:(NSString *)_data; +- (NSString *)contentString; + +@end @interface SOGoOpenIdSession : SOGoObject { @@ -47,6 +63,7 @@ NSString *openIdClient; NSString *openIdClientSecret; NSString *openIdEmailParam; + NSString *openIdHttpVersion; BOOL openIdEnableRefreshToken; BOOL sendDomainInfo; @@ -80,7 +97,7 @@ - (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; diff --git a/SoObjects/SOGo/SOGoOpenIdSession.m b/SoObjects/SOGo/SOGoOpenIdSession.m index 38710f4a1..6c6f2b881 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,7 +30,6 @@ #import - #import #import @@ -40,6 +42,60 @@ 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 andStatus:(unsigned int )_status{ + if ((self = [self init])) { + [self setStatus: _status]; + [self setContent: _data]; + } + 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; +} + +@end + @implementation SOGoOpenIdSession /// Check if all required parameters to set up a OpenIdSession are in sogo.conf @@ -72,6 +128,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 +187,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]; @@ -150,65 +208,179 @@ static BOOL SOGoOpenIDDebugEnabled = YES; } -- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint +// - (WOResponse *) _performOpenIdRequest: (NSString *) endpoint +// method: (NSString *) method +// headers: (NSDictionary *) headers +// body: (NSData *) body +// { +// NSURL *url; +// 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]; + +// request = [[WORequest alloc] initWithMethod: method +// uri: [endpoint hostlessURL] +// httpVersion: self->openIdHttpVersion +// 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 +// { +// [self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint]; +// return nil; +// } +// } + +- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint method: (NSString *) method headers: (NSDictionary *) headers body: (NSData *) body { NSURL *url; + NSMutableData *buffer; + 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; + 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); + } + + 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) + { + curl_easy_setopt(curl, CURLOPT_POST, 1); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, [body bytes]); + } + + //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]; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_function); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + 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]; + response = [response initWithResponse: nil 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]; + + 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 +670,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; @@ -566,7 +739,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 +813,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES; - (NSMutableDictionary *) fetchUserInfo { NSString *location, *auth, *content; - WOResponse *response; + SimpleOpenIdResponse *response; + // WOResponse *response; NSUInteger status; NSMutableDictionary *result; NSDictionary *profile, *headers; 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])