91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott/*
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * The contents of this file are subject to the terms of the Common Development and
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * Distribution License (the License). You may not use this file except in compliance with the
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * License.
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott *
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * specific language governing permission and limitations under the License.
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott *
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * When distributing Covered Software, include this CDDL Header Notice in each file and include
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * Header, with the fields enclosed by brackets [] replaced by your own identifying
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * information: "Portions copyright [year] [name of copyright owner]".
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott *
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * Copyright 2016 ForgeRock AS.
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott */
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott
306fc147c159b5ea1a92aa9466cd30a9bf743fe0Craig McDonnell#import "FRADateUtils.h"
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell#import "FRAIdentityDatabase.h"
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings#import "FRAMessageUtils.h"
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell#import "FRAModelObjectProtected.h"
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott#import "FRANotification.h"
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings#import "FRAPushMechanism.h"
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott/*!
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * All notifications are expected to be able to transition from the initial state
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott * of pending, to the final state of approved or denied.
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott */
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings@implementation FRANotification {
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings NSDateFormatter *formatter;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell BOOL _approved;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell BOOL _pending;
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings}
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell@synthesize approved = _approved;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell@synthesize pending = _pending;
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings- (instancetype)initWithDatabase:(FRAIdentityDatabase *)database identityModel:(FRAIdentityModel *)identityModel messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive loadBalancerCookieData:(NSString *)loadBalancerCookie pending:(BOOL)pendingState approved:(BOOL)approvedState {
f877f6ca2428244a6d0954a1dbef471577b32c60Diego Colantoni self = [super initWithDatabase:database identityModel:identityModel];
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott if (self) {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell _pending = pendingState;
465ea459a87d4605e145d8f45b6a9c104b696e3bCraig McDonnell _approved = approvedState;
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings _messageId = messageId;
1d464fc27913cfdeb6e09c8ab5d06ada64f94d55Ken Stubbings _challenge = challenge;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell _timeReceived = timeReceived;
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell _timeToLive = timeToLive;
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni _timeExpired = [timeReceived dateByAddingTimeInterval:timeToLive];
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings _loadBalancerCookie = loadBalancerCookie;
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott }
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott return self;
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott}
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings- (instancetype)initWithDatabase:(FRAIdentityDatabase *)database identityModel:(FRAIdentityModel *)identityModel messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive loadBalancerCookieData:(NSString *)loadBalancerCookie{
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings return [self initWithDatabase:database identityModel:identityModel messageId:messageId challenge:challenge timeReceived:timeReceived timeToLive:timeToLive loadBalancerCookieData:loadBalancerCookie pending:YES approved:NO];
465ea459a87d4605e145d8f45b6a9c104b696e3bCraig McDonnell}
465ea459a87d4605e145d8f45b6a9c104b696e3bCraig McDonnell
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings+ (instancetype)notificationWithDatabase:(FRAIdentityDatabase *)database identityModel:(FRAIdentityModel *)identityModel messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive loadBalancerCookieData:(NSString *)loadBalancerCookie pending:(BOOL)pendingState approved:(BOOL)approvedState{
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings return [[FRANotification alloc] initWithDatabase:database identityModel:identityModel messageId:messageId challenge:challenge timeReceived:timeReceived timeToLive:timeToLive loadBalancerCookieData:loadBalancerCookie pending:pendingState approved:approvedState];
465ea459a87d4605e145d8f45b6a9c104b696e3bCraig McDonnell}
465ea459a87d4605e145d8f45b6a9c104b696e3bCraig McDonnell
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings+ (instancetype)notificationWithDatabase:(FRAIdentityDatabase *)database identityModel:(FRAIdentityModel *)identityModel messageId:(NSString *)messageId challenge:(NSString *)challenge timeReceived:(NSDate *)timeReceived timeToLive:(NSTimeInterval)timeToLive loadBalancerCookieData:(NSString *)loadBalancerCookie{
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings return [[FRANotification alloc] initWithDatabase:database identityModel:identityModel messageId:messageId challenge:challenge timeReceived:timeReceived timeToLive:timeToLive loadBalancerCookieData:loadBalancerCookie pending:YES approved:NO];
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell}
a3970d0ea62388e4ede01470a6436eb5c6c92353Craig McDonnell
6c1420dd55f69d09f39dd213ee6c97ba901b8d92Craig McDonnell- (NSString *)age {
306fc147c159b5ea1a92aa9466cd30a9bf743fe0Craig McDonnell return [[[FRADateUtils alloc] init] ageOfEventTime:self.timeReceived];
6c1420dd55f69d09f39dd213ee6c97ba901b8d92Craig McDonnell}
6c1420dd55f69d09f39dd213ee6c97ba901b8d92Craig McDonnell
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni- (BOOL)approveWithHandler:(void (^)(NSInteger, NSError *))handler error:(NSError *__autoreleasing*)error {
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni return [self sendAuthenticationResponse:YES handler:handler error:error];
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell}
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni- (BOOL)denyWithHandler:(void (^)(NSInteger, NSError *))handler error:(NSError *__autoreleasing*)error {
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni return [self sendAuthenticationResponse:NO handler:handler error:error];
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell}
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni- (BOOL)sendAuthenticationResponse:(BOOL)approved handler:(void (^)(NSInteger, NSError *))handler error:(NSError *__autoreleasing*)error {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell _approved = approved;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell _pending = NO;
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell if ([self isStored]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott if (![self.database updateNotification:self error:error]) {
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott return NO;
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott }
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell FRAPushMechanism *mechanism = (FRAPushMechanism *)self.parent;
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings if (mechanism) {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell data[@"response"] = [FRAMessageUtils generateChallengeResponse:self.challenge secret:mechanism.secret];
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell if (!approved) {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell data[@"deny"] = @YES;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell }
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings [FRAMessageUtils respondWithEndpoint:mechanism.authEndpoint
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings base64Secret:mechanism.secret
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell messageId:self.messageId
5d37db6a3aca50ba14cba8909d3ae44f7d43e407Ken Stubbings loadBalancerCookieData:self.loadBalancerCookie
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings data:data
6a2ae9c7fb4d2c40d75cab0edaf940f22c18224fDiego Colantoni handler:handler];
a1e92b2783be4bfeb0c7e267223cc7779a6f324cKen Stubbings }
415243fbc81341293a852ff6aa14e9608d08685cCraig McDonnell }
721bb987c406979bcfe705fa1ca8d54497d40fcbRobert Wapshott return YES;
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott}
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni- (BOOL)isPending {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell return _pending && ![self isExpired];
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni}
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni- (BOOL)isExpired {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell return _pending && [[NSDate date] timeIntervalSinceDate:_timeExpired] > 0;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell}
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell- (BOOL)isApproved {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell return !_pending && _approved;
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell}
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell- (BOOL)isDenied {
cc2ae888007384c94072d7864e53548dd2840d33Craig McDonnell return !_pending && !_approved;
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni}
3cb6a584a87fa8fec140b0bb20dd91731d13e751Diego Colantoni
91f0e3cb60de3eba8cbb70c7e36cc0df22d71f5bRobert Wapshott@end