Add OIDC nonce support (#4183)

This commit is contained in:
Chuan Ren authored and GitHub committed 2019-10-29 13:03:37 -07:00
1 parent 2cac1f520e
commit ffe4a3a5b4
11 files changed
+125 -2

No files matched your search

@@ -26,6 +26,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface FIROAuthCredential ()
@property(nonatomic, nullable) NSString *rawNonce;
- (nullable instancetype)initWithProvider:(NSString *)provider NS_UNAVAILABLE;
@end
@@ -40,12 +42,14 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithProviderID:(NSString *)providerID
IDToken:(nullable NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
secret:(nullable NSString *)secret
pendingToken:(nullable NSString *)pendingToken {
self = [super initWithProvider:providerID];
if (self) {
_IDToken = IDToken;
_rawNonce = rawNonce;
_accessToken = accessToken;
_pendingToken = pendingToken;
_secret = secret;
@@ -56,8 +60,12 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithProviderID:(NSString *)providerID
sessionID:(NSString *)sessionID
OAuthResponseURLString:(NSString *)OAuthResponseURLString {
self =
[self initWithProviderID:providerID IDToken:nil accessToken:nil secret:nil pendingToken:nil];
self = [self initWithProviderID:providerID
IDToken:nil
rawNonce:nil
accessToken:nil
secret:nil
pendingToken:nil];
if (self) {
_OAuthResponseURLString = OAuthResponseURLString;
_sessionID = sessionID;
@@ -71,6 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
response.oauthSecretToken.length) {
return [self initWithProviderID:response.providerID
IDToken:response.oauthIDToken
rawNonce:nil
accessToken:response.oauthAccessToken
secret:response.oauthSecretToken
pendingToken:response.pendingToken];
@@ -80,6 +89,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
request.providerIDToken = _IDToken;
request.providerRawNonce = _rawNonce;
request.providerAccessToken = _accessToken;
request.requestURI = _OAuthResponseURLString;
request.sessionID = _sessionID;
@@ -95,11 +105,13 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
NSString *IDToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"IDToken"];
NSString *rawNonce = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"rawNonce"];
NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"];
NSString *pendingToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"pendingToken"];
NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"];
self = [self initWithProviderID:self.provider
IDToken:IDToken
rawNonce:rawNonce
accessToken:accessToken
secret:secret
pendingToken:pendingToken];
@@ -108,6 +120,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.IDToken forKey:@"IDToken"];
[aCoder encodeObject:self.IDToken forKey:@"rawNonce"];
[aCoder encodeObject:self.accessToken forKey:@"accessToken"];
[aCoder encodeObject:self.pendingToken forKey:@"pendingToken"];
[aCoder encodeObject:self.secret forKey:@"secret"];
@@ -46,12 +46,14 @@ NS_ASSUME_NONNULL_BEGIN
@brief Designated initializer.
@param providerID The provider ID associated with the credential being created.
@param IDToken The ID Token associated with the credential being created.
@param rawNonce The raw nonce associated with the Auth credential being created.
@param accessToken The access token associated with the credential being created.
@param secret The secret associated with the credential being created.
@param pendingToken The pending token associated with the credential being created.
*/
- (instancetype)initWithProviderID:(NSString *)providerID
IDToken:(nullable NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
secret:(nullable NSString *)secret
pendingToken:(nullable NSString *)pendingToken NS_DESIGNATED_INITIALIZER;
@@ -71,6 +71,7 @@ static NSString *const kAuthTypeSignInWithRedirect = @"signInWithRedirect";
accessToken:(nullable NSString *)accessToken {
return [[FIROAuthCredential alloc] initWithProviderID:providerID
IDToken:IDToken
rawNonce:nil
accessToken:accessToken
secret:nil
pendingToken:nil];
@@ -80,11 +81,35 @@ static NSString *const kAuthTypeSignInWithRedirect = @"signInWithRedirect";
accessToken:(NSString *)accessToken {
return [[FIROAuthCredential alloc] initWithProviderID:providerID
IDToken:nil
rawNonce:nil
accessToken:accessToken
secret:nil
pendingToken:nil];
}
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken {
return [[FIROAuthCredential alloc] initWithProviderID:providerID
IDToken:IDToken
rawNonce:rawNonce
accessToken:accessToken
secret:nil
pendingToken:nil];
}
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce {
return [[FIROAuthCredential alloc] initWithProviderID:providerID
IDToken:IDToken
rawNonce:rawNonce
accessToken:nil
secret:nil
pendingToken:nil];
}
+ (instancetype)providerWithProviderID:(NSString *)providerID {
return [[self alloc]initWithProviderID:providerID auth:[FIRAuth auth]];
}
@@ -342,6 +342,11 @@ static NSString *const kInvalidSessionInfoErrorMessage = @"INVALID_SESSION_INFO"
*/
static NSString *const kSessionExpiredErrorMessage = @"SESSION_EXPIRED";
/** @var kMissingOrInvalidNonceErrorMessage
@brief This is the error message the server will respond with if the nonce is missing or invalid.
*/
static NSString *const kMissingOrInvalidNonceErrorMessage = @"MISSING_OR_INVALID_NONCE";
/** @var kMissingAppTokenErrorMessage
@brief This is the error message the server will respond with if the APNS token is missing in a
verifyClient request.
@@ -1176,6 +1181,10 @@ static id<FIRAuthBackendImplementation> gBackendImplementation;
return [FIRAuthErrorUtils captchaCheckFailedErrorWithMessage:serverErrorMessage];
}
if ([shortErrorMessage isEqualToString:kMissingOrInvalidNonceErrorMessage]) {
return [FIRAuthErrorUtils missingOrInvalidNonceErrorWithMessage:serverDetailErrorMessage];
}
// In this case we handle an error that might be specified in the underlying errors dictionary,
// the error message in determined based on the @c reason key in the dictionary.
if (errorDictionary[kErrorsKey]) {
@@ -66,6 +66,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, copy, nullable) NSString *providerIDToken;
/** @property providerRawNonce
@brief An raw nonce from the IDP.
*/
@property(nonatomic, copy, nullable) NSString *providerRawNonce;
/** @property returnIDPCredential
@brief Whether the response should return the IDP credential directly.
*/
@@ -33,6 +33,11 @@ static NSString *const kProviderIDKey = @"providerId";
*/
static NSString *const kProviderIDTokenKey = @"id_token";
/** @var kProviderNonceKey
@brief The key for the "nonce" value in the request.
*/
static NSString *const kProviderNonceKey = @"nonce";
/** @var kProviderAccessTokenKey
@brief The key for the "access_token" value in the request.
*/
@@ -115,6 +120,11 @@ static NSString *const kSessionIDKey = @"sessionId";
value:_providerIDToken]];
}
if (_providerRawNonce) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderNonceKey
value:_providerRawNonce]];
}
if (_providerAccessToken) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderAccessTokenKey
value:_providerAccessToken]];
@@ -343,6 +343,10 @@ typedef NS_ENUM(NSInteger, FIRAuthErrorCode) {
*/
FIRAuthErrorCodeGameKitNotLinked = 17076,
/** Indicates that the nonce is missing or invalid.
*/
FIRAuthErrorCodeMissingOrInvalidNonce = 17094,
/** Indicates an error for when the client identifier is missing.
*/
FIRAuthErrorCodeMissingClientIdentifier = 17993,
@@ -85,6 +85,35 @@ NS_SWIFT_NAME(OAuthProvider)
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
accessToken:(NSString *)accessToken;
/** @fn credentialWithProviderID:IDToken:rawNonce:accessToken:
@brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID, ID
token, raw nonce and access token.
@param providerID The provider ID associated with the Auth credential being created.
@param IDToken The IDToken associated with the Auth credential being created.
@param rawNonce The raw nonce associated with the Auth credential being created.
@param accessToken The accessstoken associated with the Auth credential be created, if
available.
@return A FIRAuthCredential for the specified provider ID, ID token and access token.
*/
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken;
/** @fn credentialWithProviderID:IDToken:rawNonce:
@brief Creates an `FIRAuthCredential` for that OAuth 2 provider identified by providerID using
an ID token and raw nonce.
@param providerID The provider ID associated with the Auth credential being created.
@param IDToken The IDToken associated with the Auth credential being created.
@param rawNonce The raw nonce associated with the Auth credential being created.
@return A FIRAuthCredential.
*/
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce;
/** @fn init
@brief This class is not meant to be initialized.
*/
@@ -556,6 +556,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status;
/** @fn missingOrInvalidNonceErrorWithMessage:
@brief Constructs an @c NSError with the code and message provided.
@param message Error message from the backend, if any.
@return The nullable NSError instance associated with the given error message, if one is found.
*/
+ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message;
@end
NS_ASSUME_NONNULL_END
@@ -463,6 +463,12 @@ static NSString *const kFIRAuthErrorMessageDynamicLinkNotActivated =
static NSString *const kFIRAuthErrorMessageRejectedCredential =
@"The request contains malformed or mismatching credentials.";
/** @var kFIRAuthErrorMessageMissingOrInvalidNonce
@brief Error message constant describing @c FIRAuthErrorCodeMissingOrInvalidNonce errors.
*/
static NSString *const kFIRAuthErrorMessageMissingOrInvalidNonce =
@"The request contains malformed or mismatched credentials.";
/** @var FIRAuthErrorDescription
@brief The error descrioption, based on the error code.
@remarks No default case so that we get a compiler warning if a new value was added to the enum.
@@ -599,6 +605,8 @@ static NSString *FIRAuthErrorDescription(FIRAuthErrorCode code) {
return kFIRAuthErrorMessageDynamicLinkNotActivated;
case FIRAuthErrorCodeRejectedCredential:
return kFIRAuthErrorMessageRejectedCredential;
case FIRAuthErrorCodeMissingOrInvalidNonce:
return kFIRAuthErrorMessageMissingOrInvalidNonce;
}
}
@@ -738,6 +746,8 @@ static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) {
return @"ERROR_DYNAMIC_LINK_NOT_ACTIVATED";
case FIRAuthErrorCodeRejectedCredential:
return @"ERROR_REJECTED_CREDENTIAL";
case FIRAuthErrorCodeMissingOrInvalidNonce:
return @"ERROR_MISSING_OR_INVALID_NONCE";
}
}
@@ -1179,6 +1189,10 @@ static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) {
return [self errorWithCode:FIRAuthInternalErrorCodeInvalidDynamicLinkDomain message:message];
}
+ (NSError *)missingOrInvalidNonceErrorWithMessage:(nullable NSString *)message {
return [self errorWithCode:FIRAuthInternalErrorCodeMissingOrInvalidNonce message:message];
}
+ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status {
NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status];
return [self errorWithCode:FIRAuthInternalErrorCodeKeychainError userInfo:@{
@@ -393,6 +393,11 @@ typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) {
FIRAuthInternalErrorCodeGameKitNotLinked =
FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeGameKitNotLinked,
/** Indicates that the nonce is missing or invalid.
*/
FIRAuthInternalErrorCodeMissingOrInvalidNonce =
FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeMissingOrInvalidNonce,
/** Indicates that a non-null user was expected as an argmument to the operation but a null
user was provided.
*/