Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions AppAuth.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Source/AppAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#import "OIDTokenResponse.h"
#import "OIDTokenUtilities.h"
#import "OIDURLSessionProvider.h"
#import "OIDEndSessionRequest.h"
#import "OIDEndSessionResponse.h"

#if TARGET_OS_TV
#elif TARGET_OS_WATCH
Expand Down
3 changes: 3 additions & 0 deletions Source/Framework/AppAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ FOUNDATION_EXPORT const unsigned char AppAuthVersionString[];
#import <AppAuth/OIDAuthStateErrorDelegate.h>
#import <AppAuth/OIDAuthorizationRequest.h>
#import <AppAuth/OIDAuthorizationResponse.h>
#import <AppAuth/OIDAuthorizationFlowSession.h>
#import <AppAuth/OIDAuthorizationService.h>
#import <AppAuth/OIDExternalUserAgent.h>
#import <AppAuth/OIDError.h>
Expand All @@ -44,6 +45,8 @@ FOUNDATION_EXPORT const unsigned char AppAuthVersionString[];
#import <AppAuth/OIDTokenRequest.h>
#import <AppAuth/OIDTokenResponse.h>
#import <AppAuth/OIDTokenUtilities.h>
#import <AppAuth/OIDEndSessionRequest.h>
#import <AppAuth/OIDEndSessionResponse.h>

#if TARGET_OS_TV
#elif TARGET_OS_WATCH
Expand Down
30 changes: 29 additions & 1 deletion Source/OIDAuthState.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
@class OIDAuthorizationRequest;
@class OIDAuthorizationResponse;
@class OIDAuthState;
@class OIDEndSessionRequest;
@class OIDEndSessionResponse;
@class OIDRegistrationResponse;
@class OIDTokenResponse;
@class OIDTokenRequest;
Expand All @@ -41,14 +43,23 @@ typedef void (^OIDAuthStateAction)(NSString *_Nullable accessToken,
NSError *_Nullable error);

/*! @brief The method called when the @c
OIDAuthState.authStateByPresentingAuthorizationRequest:presentingViewController:callback:
OIDAuthState.authStateByPresentingAuthorizationRequest:externalUserAgent:callback:
method has completed or failed.
@param authState The auth state, if the authorization request succeeded.
@param error The error if an error occurred.
*/
typedef void (^OIDAuthStateAuthorizationCallback)(OIDAuthState *_Nullable authState,
NSError *_Nullable error);

/*! @brief The method called when the @c OIDAuthState.presentEndSessionRequest:externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
callback has completed or failed.
method has completed or failed.
@param endSessionResponse The response to the end session request from the OP.
@param error The error if an error occurred.
*/
typedef void (^OIDEndSessionCallback)(OIDEndSessionResponse *_Nullable endSessionResponse,
NSError *_Nullable error);

/*! @brief A convenience class that retains the auth state between @c OIDAuthorizationResponse%s
and @c OIDTokenResponse%s.
*/
Expand Down Expand Up @@ -284,6 +295,23 @@ typedef void (^OIDAuthStateAuthorizationCallback)(OIDAuthState *_Nullable authSt
- (void)withFreshTokensPerformAction:(OIDAuthStateAction)action
__deprecated_msg("Use OIDAuthState.performActionWithFreshTokens:");


/*! @brief Presents a RP-initiated logout using the external user agent.
@param endSessionRequest The end session request to present.
@param externalUserAgent A external user agent that can present an external user-agent request.
@param callback The method called when the request has completed or failed.
@return A @c OIDExternalUserAgentSession instance which will terminate when it receives a
@c OIDExternalUserAgentSession.cancel message, or after processing a
@c OIDExternalUserAgentSession.resumeExternalUserAgentFlowWithURL: message.
@discussion Afer a successful ending of the session, it invalidates the @c OIDAuthState.
Remove references to this instance. Hence, a new authorization flow is required
to retrieve a new instance of @c OIDAuthState. R
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
*/
- (id<OIDExternalUserAgentSession>)presentEndSessionRequest:(OIDEndSessionRequest *)endSessionRequest
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
callback:(OIDEndSessionCallback)callback;

@end

NS_ASSUME_NONNULL_END
31 changes: 30 additions & 1 deletion Source/OIDAuthState.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
#import "OIDAuthorizationResponse.h"
#import "OIDAuthorizationService.h"
#import "OIDDefines.h"
#import "OIDEndSessionFlowSession.h"
#import "OIDEndSessionRequest.h"
#import "OIDError.h"
#import "OIDErrorUtilities.h"
#import "OIDExternalUserAgent.h"
#import "OIDRegistrationResponse.h"
#import "OIDTokenRequest.h"
#import "OIDTokenResponse.h"
Expand Down Expand Up @@ -310,12 +313,16 @@ - (BOOL)isAuthorized {

- (void)updateWithRegistrationResponse:(OIDRegistrationResponse *)registrationResponse {
_lastRegistrationResponse = registrationResponse;
[self resetState];
[self didChangeState];
}

- (void)resetState {
_refreshToken = nil;
_scope = nil;
_lastAuthorizationResponse = nil;
_lastTokenResponse = nil;
_authorizationError = nil;
[self didChangeState];
}

- (void)updateWithAuthorizationResponse:(nullable OIDAuthorizationResponse *)authorizationResponse
Expand Down Expand Up @@ -532,6 +539,28 @@ - (BOOL)isTokenFresh {
return tokenFresh;
}

#pragma mark - End session

- (id<OIDExternalUserAgentSession>)presentEndSessionRequest:(OIDEndSessionRequest *)endSessionRequest
externalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
callback:(OIDEndSessionCallback)callback {
OIDEndSessionFlowSession *session = [[OIDEndSessionFlowSession alloc] initWithRequest:endSessionRequest];
OIDEndSessionCallback wrappedCallback = ^(OIDEndSessionResponse *_Nullable endSessionResponse,
NSError *_Nullable error) {
if (!error) {
[self resetState];
[self didChangeState];
}

callback(endSessionResponse, error);
};

// presents the end session request
[session presentEndSessionWithExternalUserAgent:externalUserAgent callback:wrappedCallback];

return session;
}

@end


53 changes: 53 additions & 0 deletions Source/OIDEndSessionFlowSession.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*! @file OIDEndSessionFlowSession.h
@brief AppAuth iOS SDK
@copyright
Copyright 2018 The AppAuth Authors. All Rights Reserved.
@copydetails
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#import "OIDAuthState.h"

@protocol OIDExternalUserAgent;
@protocol OIDExternalUserAgentSession;

@class OIDEndSessionRequest;
@class OIDEndSessionResponse;

NS_ASSUME_NONNULL_BEGIN

/*! @brief Flow handler for the @c OIDEndSessionRequest
@see http://openid.net/specs/openid-connect-session-1_0.html#RPLogout
*/
@interface OIDEndSessionFlowSession : NSObject<OIDExternalUserAgentSession>

/*! @internal
@brief Unavailable. Please use @c initWithRequest:.
*/
- (instancetype)init NS_UNAVAILABLE;

/*! @brief Create new end session flow
@param request The end session request
*/
- (instancetype)initWithRequest:(OIDEndSessionRequest *)request NS_DESIGNATED_INITIALIZER;

/*! @brief Present the sesion request on the provided @c OIDExternalUserAgent.
@param externalUserAgent The user agent for presenting the request.
@param endSessionFlowCallback The callback that will be triggered after the session is completed.
*/
- (void)presentEndSessionWithExternalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
callback:(OIDEndSessionCallback)endSessionFlowCallback;

@end

NS_ASSUME_NONNULL_END
163 changes: 163 additions & 0 deletions Source/OIDEndSessionFlowSession.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*! @file OIDEndSessionFlowSession.m
@brief AppAuth iOS SDK
@copyright
Copyright 2018 The AppAuth Authors. All Rights Reserved.
@copydetails
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#import "OIDEndSessionFlowSession.h"

#import "OIDDefines.h"
#import "OIDEndSessionRequest.h"
#import "OIDEndSessionResponse.h"
#import "OIDErrorUtilities.h"
#import "OIDExternalUserAgent.h"
#import "OIDURLQueryComponent.h"

NS_ASSUME_NONNULL_BEGIN

@interface OIDEndSessionFlowSession() {
// private variables
OIDEndSessionRequest *_request;
id<OIDExternalUserAgent> _externalUserAgent;
OIDEndSessionCallback _pendingEndSessionFlowCallback;
}
@end

@implementation OIDEndSessionFlowSession

- (instancetype)initWithRequest:(OIDEndSessionRequest *)request {
self = [super init];
if (self) {
_request = [request copy];
}
return self;
}

- (void)presentEndSessionWithExternalUserAgent:(id<OIDExternalUserAgent>)externalUserAgent
callback:(OIDEndSessionCallback)endSessionFlowCallback {
_externalUserAgent = externalUserAgent;
_pendingEndSessionFlowCallback = endSessionFlowCallback;
BOOL authorizationFlowStarted =
[_externalUserAgent presentExternalUserAgentRequest:_request session:self];
if (!authorizationFlowStarted) {
NSError *safariError = [OIDErrorUtilities errorWithCode:OIDErrorCodeSafariOpenError
underlyingError:nil
description:@"Unable to open Safari."];
[self didFinishWithResponse:nil error:safariError];
}
}

- (void)cancel {
[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
NSError *error = [OIDErrorUtilities
errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
underlyingError:nil
description:nil];
[self didFinishWithResponse:nil error:error];
}];
}

- (BOOL)shouldHandleURL:(NSURL *)URL {
NSURL *standardizedURL = [URL standardizedURL];
NSURL *standardizedRedirectURL = [_request.postLogoutRedirectURL standardizedURL];

return OIDIsEqualIncludingNil(standardizedURL.scheme, standardizedRedirectURL.scheme) &&
OIDIsEqualIncludingNil(standardizedURL.user, standardizedRedirectURL.user) &&
OIDIsEqualIncludingNil(standardizedURL.password, standardizedRedirectURL.password) &&
OIDIsEqualIncludingNil(standardizedURL.host, standardizedRedirectURL.host) &&
OIDIsEqualIncludingNil(standardizedURL.port, standardizedRedirectURL.port) &&
OIDIsEqualIncludingNil(standardizedURL.path, standardizedRedirectURL.path);
}

- (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL {
// rejects URLs that don't match redirect (these may be completely unrelated to the authorization)
if (![self shouldHandleURL:URL]) {
return NO;
}
// checks for an invalid state
if (!_pendingEndSessionFlowCallback) {
[NSException raise:OIDOAuthExceptionInvalidAuthorizationFlow
format:@"%@", OIDOAuthExceptionInvalidAuthorizationFlow, nil];
}

OIDURLQueryComponent *query = [[OIDURLQueryComponent alloc] initWithURL:URL];

NSError *error;
OIDEndSessionResponse *response = nil;

// checks for an OAuth error response as per RFC6749 Section 4.1.2.1
if (query.dictionaryValue[OIDOAuthErrorFieldError]) {
error = [OIDErrorUtilities OAuthErrorWithDomain:OIDOAuthAuthorizationErrorDomain
OAuthResponse:query.dictionaryValue
underlyingError:nil];
}

// no error, should be a valid OAuth 2.0 response
if (!error) {
response = [[OIDEndSessionResponse alloc] initWithRequest:_request
parameters:query.dictionaryValue];

// verifies that the state in the response matches the state in the request, or both are nil
if (!OIDIsEqualIncludingNil(_request.state, response.state)) {
NSMutableDictionary *userInfo = [query.dictionaryValue mutableCopy];
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
"response %@",
_request.state,
response.state,
response];
response = nil;
error = [NSError errorWithDomain:OIDOAuthAuthorizationErrorDomain
code:OIDErrorCodeOAuthAuthorizationClientError
userInfo:userInfo];
}
}

[_externalUserAgent dismissExternalUserAgentAnimated:YES completion:^{
[self didFinishWithResponse:response error:error];
}];

return YES;
}

- (void)failExternalUserAgentFlowWithError:(NSError *)error {
[self didFinishWithResponse:nil error:error];
}

/*! @brief Invokes the pending callback and performs cleanup.
@param response The authorization response, if any to return to the callback.
@param error The error, if any, to return to the callback.
*/
- (void)didFinishWithResponse:(nullable OIDEndSessionResponse *)response
error:(nullable NSError *)error {
OIDEndSessionCallback callback = _pendingEndSessionFlowCallback;
_pendingEndSessionFlowCallback = nil;
_externalUserAgent = nil;
if (callback) {
callback(response, error);
}
}

- (void)failAuthorizationFlowWithError:(NSError *)error {
[self failExternalUserAgentFlowWithError:error];
}

- (BOOL)resumeAuthorizationFlowWithURL:(NSURL *)URL {
return [self resumeExternalUserAgentFlowWithURL:URL];
}

@end

NS_ASSUME_NONNULL_END
Loading