AppAuth-iOS: Unarchive with unarchivedObjectOfClass:fromData:error: fails with Google IdP

Describe the bug I replaced the deprecated archiving/unarchiving method calls in the example. unarchivedObjectOfClass:fromData:error: instead of unarchivedObjectWithData: for unarchiving.

While running the app, OIDAuthorizationRequest.m:147 asserts:

2019-11-18 22:40:44.589307-0500 Example-iOS_ObjC[9060:362850] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The response_type "(null)" isn't supported. AppAuth only supports the "code" or "code id_token" response_type.'

By commenting this assert, I get the following error from the unarchive method:

Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'NS.objects' was of unexpected class 'NSArray'. Allowed classes are '{(
    OIDServiceDiscovery
)}'." UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'NSArray'. Allowed classes are '{(
    OIDServiceDiscovery
)}'.}

This seems related to the bug described in #466.

To Reproduce Steps to reproduce the behavior:

  1. Run example app
  2. Authorize
  3. Kill app
  4. Open and see error

Smartphone (please complete the following information):

  • Device: iPhone 11 Simulator
  • OS: 13.0

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 15 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Hello,

All users of this library need to persist OIDAuthState, so it would be great if the library would support serialization of this class out of the box.

Today, developers are bound to use deprecated NSCoding apis, because NSSecureCoding support is broken. The Swift compiler does not allow to silence deprecation warnings. This is not a great situation.

In this repository, there are several pull requests that attempt at fixing this issue, at various levels of completion, and all blocked at some stage or another.

Clearly community contributions are unable to fix this problem.

May I suggest that some core contributor would act as a benevolent contributor, take this issue seriously, and provides a reliable serialization solution for OIDAuthState? I can’t point at anybody, of course, but maybe @petea could provide some guidance?

Hi, I’m new here.

I fixed the problem by changing in flie : OIDServiceConfiguration.m line : 188

OIDServiceDiscovery *discoveryDocument = [aDecoder decodeObjectOfClass:[OIDServiceDiscovery class]
                                                                  forKey:kDiscoveryDocumentKey];

to

OIDServiceDiscovery *discoveryDocument = [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:[OIDServiceDiscovery class], [NSDictionary class], [NSArray class], nil]
                                                                  forKey:kDiscoveryDocumentKey];

Wish to help.

In line with what others have reported, I’m able to get get it to work by using NSKeyedArchiver.unarchiveTopLevelObjectWithData() instead of NSKeyedArchiver.unarchivedObject(ofClass:,from:).

Specifically, I have a class AuthState that packages an OIDAuthState and an OIDServiceConfiguration to serialize them together:

class AuthState: NSSecureCoding {
    let state: OIDAuthState
    let config: OIDServiceConfiguration
    
    <implementation of init, NSSecureCoding>
}

let serializedAuthState: Data = try NSKeyedArchiver.archivedData(withRootObject: anAuthState, requiringSecureCoding: true)

// Decodes incorrectly, hits `NSAssert` on `nil` value for `response_type` as described above.
let authState: AuthState = try NSKeyedUnarchiver.unarchivedObject(ofClass: AuthState.self, from: serializedAuthState)

// Succeeds
let authState: AuthState = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(serializedAuthState) as! AuthState

As far as I can tell the implementation in AppAuth for those types is good, but obviously we’re missing something. It’s especially interesting to me that the configuration property decodes correctly (per previous comment), and then all the NSString*s come back as nil.

For the moment I’m going to work around this with the workaround as above, but given that method is also deprecated (although not yet removed as of iOS 14.3) a fix here will have some urgency.

For the moment I’m going to work around this with the workaround as above, but given that method is also deprecated (although not yet removed as of iOS 14.3) a fix here will have some urgency.

Agree. At the very least, the documentation and the sample code should be updated

From what I can tell, the problem has to do with the implementation of NSSecureCoding; while unarchiving, the code is listing allowed classes, but that doesn’t match what’s actually encoded in the archive.

You can work around this by manually creating an NSKeyedUnarchiver instance, setting its requiresSecureCoding property to false, and using that to unarchive the blob.