FRAModelsFromDatabase.m revision 55abfb9b58693eddac5205e74aac84f50c9798d2
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * The contents of this file are subject to the terms of the Common Development and
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * Distribution License (the License). You may not use this file except in compliance with the
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * specific language governing permission and limitations under the License.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * When distributing Covered Software, include this CDDL Header Notice in each file and include
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * Header, with the fields enclosed by brackets [] replaced by your own identifying
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * information: "Portions copyright [year] [name of copyright owner]".
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * Copyright 2016 ForgeRock AS.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FMDatabase.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAError.h"
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott#import "FRAFMDatabaseConnectionHelper.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAHMACAlgorithm.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAIdentity.h"
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott#import "FRAModelObjectProtected.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAModelsFromDatabase.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRANotification.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAOathMechanism.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRAPushMechanism.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott#import "FRASerialization.h"
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * The parsing logic operates as follows:
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * Perform SQL query to fetch all Identities, Mechanisms and Notifications where each
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * Identity may have multiple associated Mechanisms and PushMechanisms may have multiple
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * associated Notifications.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * The function will re-use matching Identities and Push Mechanisms as appropriate.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott * TODO: Split into smaller functions.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott+ (NSArray<FRAIdentity*> *)getAllIdentitiesFrom:(FRAFMDatabaseConnectionHelper *)sqlDatabase including:(FRAIdentityDatabase *)identityDatabase catchingErrorsWith:(NSError *__autoreleasing *)error {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *sql = [FRAFMDatabaseConnectionHelper readSchema:@"read_all" withError:error];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Open Database
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott database = [sqlDatabase getConnectionWithError:error];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Perform update
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott FMResultSet *results = [database executeQuery:sql];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott [FRAError createErrorForLastFailure:database withError:error];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Output rows for debugging purposes.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // TODO: Sanitise data.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSLog(@"Reading all rows from the database:");
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSMutableArray* identities = [[NSMutableArray alloc] init];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *issuer = [FRASerialization nullToEmpty:[results stringForColumn:@"issuer"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *accountName = [FRASerialization nullToEmpty:[results stringForColumn:@"accountName"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *imageURL = [FRASerialization nullToEmpty:[results stringForColumn:@"imageURL"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *bgColor = [FRASerialization nullToEmpty:[results stringForColumn:@"bgColor"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *type = [FRASerialization nullToEmpty:[results stringForColumn:@"type"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSInteger version = [results intForColumn:@"version"];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *mechanismUID = [FRASerialization nullToEmpty:[results stringForColumn:@"mechanismUID"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *optionsJSON = [FRASerialization nullToEmpty:[results stringForColumn:@"options"]];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // Notification
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *timeReceived = [FRASerialization nullToEmpty:[results stringForColumn:@"timeReceived"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *timeExpired = [FRASerialization nullToEmpty:[results stringForColumn:@"timeExpired"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *data = [FRASerialization nullToEmpty:[results stringForColumn:@"data"]];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott int pending = [results intForColumn:@"pending"];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott int approved = [results intForColumn:@"approved"];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSLog(@"[%d] %@ %@ %@ %@ %@ %ld %@ %@ %@ %d %d",
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Create an Identity
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott image:[[NSURL alloc]initWithString:imageURL]
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Check if we already have generated this identity, in which case re-use.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if ([newIdentity.issuer isEqualToString:identity.issuer] && [newIdentity.accountName isEqualToString:identity.accountName]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Formatter for parsing numbers from Strings.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Create the Mechanism
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if ([type isEqualToString:@"hotp"] || [type isEqualToString:@"totp"]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // TODO: Null checking on errors.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Options Map is a String to String mapping stored in JSON.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if (![FRASerialization deserializeJSON:optionsJSON intoDictionary:&optionsMap error:error]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Secret Key - Base 64 encoded bytes
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *secretValue = [optionsMap objectForKey:OATH_MECHANISM_SECRET];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSData* secret = [FRASerialization deserializeBytes:secretValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Algorithm - String enumeration
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *algorithmValue = [optionsMap objectForKey:OATH_MECHANISM_ALGORITHM];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott CCHmacAlgorithm algorithm = [FRAHMACAlgorithm fromString:algorithmValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Digits - String value of Integer
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *digitsValue = [optionsMap objectForKey:OATH_MECHANISM_DIGITS];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott int digits = [[numberFormatter numberFromString:digitsValue] intValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Period - String value of unsigned Integer
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *periodValue = [optionsMap objectForKey:OATH_MECHANISM_PERIOD];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott u_int32_t period = [[numberFormatter numberFromString:periodValue] unsignedIntValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Counter - String value of unsigned Long Long
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *counterValue = [optionsMap objectForKey:OATH_MECHANISM_COUNTER];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott u_int64_t counter = [[numberFormatter numberFromString:counterValue] unsignedLongLongValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott FRAOathMechanism *newMechanism = [FRAOathMechanism
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Note: We are not de-duplicating OATH Mechanism becuase they will not be duplicated in the SQL results.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if (![newIdentity addMechanism:newMechanism error:error]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott } else if ([type isEqualToString:@"push"]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Options Map is a String to String mapping stored in JSON.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if (![FRASerialization deserializeJSON:optionsJSON intoDictionary:&optionsMap error:error]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Secret stored as String (Base64?)
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *secretValue = [optionsMap objectForKey:PUSH_MECHANISM_SECRET];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Auth Endpoint as string
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *authEndpointValue = [optionsMap objectForKey:PUSH_MECHANISM_AUTH_END_POINT];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Version as string
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSString *versionString = [optionsMap objectForKey:PUSH_MECHANISM_VERSION];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott NSInteger version = [[numberFormatter numberFromString:versionString] integerValue];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott FRAPushMechanism *newMechanism = [FRAPushMechanism pushMechanismWithDatabase:identityDatabase authEndpoint:authEndpointValue secret:secretValue version:version];
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Check to see if we already have this PushMechanism present, otherwise add it in.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott for (FRAMechanism *mechanism in newIdentity.mechanisms) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if ([mechanism isKindOfClass:[FRAPushMechanism class]]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott FRAPushMechanism *pushMechanism = (FRAPushMechanism *)mechanism;
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if ([pushMechanism.mechanismUID isEqualToString:newMechanism.mechanismUID]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if (![newIdentity addMechanism:newMechanism error:error]) {
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // If we have a notification, parse and create the Notification for the Push Mechanism.
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott // Note: Notifications can only currently exist for PushMechanisms.
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott if (timeReceived != nil && [timeReceived length] > 0) {
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // Time stamp of the notification
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott NSDate *received = [NSDate dateWithTimeIntervalSince1970:[timeReceived doubleValue]];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott if (![FRASerialization deserializeJSON:data intoDictionary:&dataMap error:error]) {
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // Data: Message ID
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott NSString *messageId = [dataMap valueForKey:NOTIFICATION_MESSAGE_ID];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // Data: Challenge
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott NSString *challenge = [[NSString alloc] initWithData:[FRASerialization deserializeBytes:[dataMap valueForKey:NOTIFICATION_PUSH_CHALLENGE]] encoding:NSUTF8StringEncoding];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott NSTimeInterval ttl = [[dataMap valueForKey:NOTIFICATION_TIME_TO_LIVE] doubleValue];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott FRANotification *notification = [FRANotification notificationWithDatabase:identityDatabase
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott if (![newMechanism addNotification:notification error:error]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott @throw [FRAError createIllegalStateException:@"Invalid mechanism"];
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott // As we have read the objects from the database, marked them as stored.
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott for (FRAMechanism *mechanism in identity.mechanisms) {
2ff6fc247a59e7bebd6f71595469a511fe7456efRobert Wapshott for (FRANotification *notification in mechanism.notifications) {