diff --git a/SoObjects/SOGo/SOGoSession.h b/SoObjects/SOGo/SOGoSession.h new file mode 100644 index 000000000..3094f619b --- /dev/null +++ b/SoObjects/SOGo/SOGoSession.h @@ -0,0 +1,46 @@ +/* SOGoSession.h - this file is part of SOGo + * + * Copyright (C) 2010-2011 Inverse inc. + * + * Author: Ludovic Marcotte + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef SOGOSESSION_H +#define SOGOSESSION_H + +#import + +@interface SOGoSession : NSObject + ++ (NSString *) valueForSessionKey: (NSString *) theSessionKey; ++ (void) setValue: (NSString *) theValue + forSessionKey: (NSString *) theSessionKey; ++ (void) deleteValueForSessionKey: (NSString *) theSessionKey; + ++ (NSString *) generateKeyForLength: (unsigned int) theLength; ++ (NSString *) securedValue: (NSString *) theValue + usingKey: (NSString *) theKey; ++ (NSString *) valueFromSecuredValue: (NSString *) theValue + usingKey: (NSString *) theKey; ++ (void) decodeValue: (NSString *) theValue + usingKey: (NSString *) theKey + login: (NSString **) theLogin + password: (NSString **) thePassword; +@end + +#endif diff --git a/SoObjects/SOGo/SOGoSession.m b/SoObjects/SOGo/SOGoSession.m new file mode 100644 index 000000000..312b128a9 --- /dev/null +++ b/SoObjects/SOGo/SOGoSession.m @@ -0,0 +1,247 @@ +/* SOGoSession.m - this file is part of SOGo + * + * Copyright (C) 2010-2011 Inverse inc. + * + * Author: Ludovic Marcotte + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "SOGoSession.h" + +#include "SOGoCache.h" + +#import +#import + +#import +#import +#import + +#import + +#include +#include +#include +#include + +// Default length in bytes +static int userKeyLength = 64; +static int sessionKeyLength = 16; + +@implementation SOGoSession + ++ (NSString *) valueForSessionKey: (NSString *) theSessionKey +{ + NSString *value, *key; + SOGoCache *cache; + + cache = [SOGoCache sharedCache]; + + key = [NSString stringWithFormat: @"session:%@", theSessionKey]; + value = [cache valueForKey: key]; + + // We go check in the database + if (!value) + { + GCSSessionsFolder *folder; + NSDictionary *d; + + folder = [[GCSFolderManager defaultFolderManager] sessionsFolder]; + d = [folder recordForEntryWithID: theSessionKey]; + + if (d) + { + // We cache back the result in memcached + value = [d objectForKey: @"c_value"]; + [cache setValue: value forKey: key]; + + // We update c_lastseen. We do this only when we get a cache miss from memcached + // and when the data was reloaded from the database to avoid updating it too often. + // This is good enough since this information would be mostly used to cleanup + // dead sessions - and not really to know when was the last time a user + // invoke an action method on SOGo. + [folder writeRecordForEntryWithID: theSessionKey + value: value + creationDate: [NSDate dateWithTimeIntervalSince1970: [[d objectForKey: @"c_creationdate"] intValue]] + lastSeenDate: [NSCalendarDate date]]; + } + } + + return value; +} + ++ (void) setValue: (NSString *) theValue + forSessionKey: (NSString *) theSessionKey +{ + GCSSessionsFolder *folder; + NSCalendarDate *now; + SOGoCache *cache; + NSString *key; + + cache = [SOGoCache sharedCache]; + + key = [NSString stringWithFormat: @"session:%@", theSessionKey]; + + [cache setValue: theValue forKey: key]; + + // We store it inside the database + folder = [[GCSFolderManager defaultFolderManager] sessionsFolder]; + + now = [NSCalendarDate date]; + [folder writeRecordForEntryWithID: theSessionKey + value: theValue + creationDate: now + lastSeenDate: now]; +} + +// +// +// ++ (void) deleteValueForSessionKey: (NSString *) theSessionKey +{ + GCSSessionsFolder *folder; + + folder = [[GCSFolderManager defaultFolderManager] sessionsFolder]; + + [folder deleteRecordForEntryWithID: theSessionKey]; + [[SOGoCache sharedCache] removeValueForKey: [NSString stringWithFormat: @"session:%@", theSessionKey]]; +} + +// +// +// ++ (NSString *) generateKeyForLength: (unsigned int) theLength +{ + char *buf; + int fd; + + fd = open("/dev/urandom", O_RDONLY); + + if (fd > 0) + { + NSData *data; + NSString *s; + + buf = (char *)malloc(theLength); + read(fd, buf, theLength); + close(fd); + + // We encode the bytes in base64 with a line lenght fixed to 1024 since + // we want to avoid folding the values + data = [NSData dataWithBytesNoCopy: buf length: theLength freeWhenDone: YES]; + + s = [[NSString alloc] initWithData: [data dataByEncodingBase64WithLineLength: 1024] + encoding: NSASCIIStringEncoding]; + return [s autorelease]; + } + + return nil; +} + +// +// The key will likely be longer than the password. We don't care +// that much about this for now. +// ++ (NSString *) securedValue: (NSString *) theValue + usingKey: (NSString *) theKey +{ + NSData *data; + NSString *s; + + char *buf, *key, *pass; + int i, klen; + + // Get the key length and its bytes + data = [theKey dataByDecodingBase64]; + key = (char *)[data bytes]; + klen = [data length]; + + // Get the key - padding it with 0 with key length + pass = (char *)malloc(klen); + memset(pass, 0, klen); + [theValue getCString: pass maxLength: klen encoding: NSUTF8StringEncoding]; + + // Target buffer + buf = (char *)malloc(klen); + + for (i = 0; i < klen; i++) + { + buf[i] = key[i] ^ pass[i]; + } + + free(pass); + + data = [NSData dataWithBytesNoCopy: buf length: klen freeWhenDone: YES]; + + s = [[NSString alloc] initWithData: [data dataByEncodingBase64WithLineLength: 1024] + encoding: NSASCIIStringEncoding]; + return [s autorelease]; +} + + ++ (NSString *) valueFromSecuredValue: (NSString *) theValue + usingKey: (NSString *) theKey +{ + NSData *data; + NSString *s; + + char *buf, *key, *pass; + int i, klen; + + // Get the key length and its bytes + data = [theKey dataByDecodingBase64]; + key = (char *)[data bytes]; + klen = [data length]; + + // Get the secured password + pass = (char *)[[theValue dataByDecodingBase64] bytes]; + + // Target buffer + buf = (char *)malloc(klen); + + for (i = 0; i < klen; i++) + { + buf[i] = key[i] ^ pass[i]; + } + + // buf is now our C string in UTF8 + s = [NSString stringWithCString: buf encoding: NSUTF8StringEncoding]; + free(buf); + + return s; +} + +// +// +// ++ (void) decodeValue: (NSString *) theValue + usingKey: (NSString *) theKey + login: (NSString **) theLogin + password: (NSString **) thePassword +{ + NSString *decodedValue; + NSRange r; + + decodedValue = [SOGoSession valueFromSecuredValue: theValue + usingKey: theKey]; + + r = [decodedValue rangeOfString: @":"]; + *theLogin = [decodedValue substringToIndex: r.location]; + *thePassword = [decodedValue substringFromIndex: r.location+1]; +} + +@end