unrecognized selector sent to instance

968 views
Skip to first unread message

Aziz Light

unread,
Mar 24, 2013, 8:16:13 PM3/24/13
to gtm-o...@googlegroups.com
Hi everybody,

Following my previous post, I redesigned the OAuth server of my app. I followed the GTM OAuth wiki and the sample app that is shipped with the library and managed to build a little app. It doesn't yet work though. Please bear in mind that I am learning how to create an iPhone app using this little project, so don't be too harsh please :) Here is the Github repo for the app: https://github.com/AzizLight/Catapult-for-iOS

Here is the problem. I have a button on the view, that is linked to the custom `signInToCatapult` method (which consequently return IBAction). Here is the code that I am referring to: https://github.com/AzizLight/Catapult-for-iOS/blob/master/Catapult%20for%20iOS/CatapultViewController.m#L46

I manage to send the authentication request, and when I get the response, the iPhone app receives it and crashes with the following error message:

2013-03-24 23:53:49.754 Catapult for iOS[65266:c07] -[NSNull length]: unrecognized selector sent to instance 0x14f2678

2013-03-24 23:53:49.754 Catapult for iOS[65266:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x14f2678'

*** First throw call stack:

(0x13c1012 0x11e6e7e 0x144c4bd 0x13b0bbc 0x13b094e 0xf074 0x185e3 0x13b51bd 0x13b50d6 0x1531a 0x1512b 0x14ae2 0x13b51bd 0x13b50d6 0x11d0a 0x1032a 0x13b51bd 0x13b50d6 0x79be 0x77ed 0x8cf2 0xcec589 0xcea652 0xceb89a 0xcea60d 0xcea785 0xc37a68 0x4a2a911 0x4a29bb3 0x4a67cda 0x13638fd 0x4a6835c 0x4a682d5 0x4952250 0x1344f3f 0x1344a39 0x1367734 0x1366f44 0x1366e1b 0x22be7e3 0x22be668 0x12affc 0x2c5d 0x2b85)

libc++abi.dylib: terminate called throwing an exception

I do not understand that error message and I do not know how to debug it at all...

Does anyone know what the problem might be please?

Greg Robbins

unread,
Mar 24, 2013, 9:49:05 PM3/24/13
to gtm-o...@googlegroups.com
The error message "-[NSNull length]: unrecognized selector sent to instance 0x14f2678" is self-explanatory. The application is unintentionally sending the -length message to an NSNull object, so the object throws an exception. This is a typical crash due to pointer or memory management errors.

The issue is unrelated to the gtm-oauth2 controllers, however, so it would be more suited to an Objective-C programming help discussion group, not to this list.

Aziz Light

unread,
Mar 25, 2013, 3:20:39 AM3/25/13
to gtm-o...@googlegroups.com
The problem is that I don't use the length method on any object/class anywhere if you see the code in the repo. That's why I thought that it was a gtm-oauth2 related error, or rather somehow my misuse of it...

But anyway, thanks for your answer.

Aziz Light

unread,
Mar 25, 2013, 5:07:23 AM3/25/13
to gtm-o...@googlegroups.com
Thanks to a StackOverflow question, I managed to pinpoint where the app breaks exactly. It breaks in GTMOAuth2Authentication.m line 652:

BOOL canAuth = [token length] > 0;

So token is nil. That means (if I'm correct) that the problem comes from the response of the OAuth 2.0 server. Now, to be able to debug this, I need to get raw JSON output of the response, so I need to add a line to the gtm-oauth2 library to be able to do that.

Where and how would I do that please?

Bill Kocik

unread,
Mar 25, 2013, 7:30:41 AM3/25/13
to gtm-o...@googlegroups.com
If the service you're interacting with is like most other OAuth services, the token won't be in JSON, it'll be a parameter on the URL you're being redirected to. I'd set a breakpoint in GTMOAuth2ViewControllerTouch at webView:shouldStartLoadWithRequest:navigationType: and see if the token is in URL. Note that you'll hit this breakpoint more than once before the final redirect that should contain the token.

Aziz Light

unread,
Mar 25, 2013, 8:04:22 AM3/25/13
to gtm-o...@googlegroups.com
Thanks for your answer. I added NSLog(@"%@", [request URL]) in GTMOAuth2ViewControllerTouch at webView:shouldStartLoadWithRequest:navigationType: (since I don't know how gdb works...) and saw that the URL of the response request is 

https://catapultcentral.com/iOSClientCallback?code=07b6ba09e3279afb878ee9532ef36c60f2888ba23bd412dcce47a75183dfa75d which seems fine to me... so I do not understand what the problem is...

Aziz Light

unread,
Mar 26, 2013, 5:20:15 AM3/26/13
to gtm-o...@googlegroups.com
I managed to make the library work by enabling refresh tokens on the OAuth server. However, I still don't understand why the library doesn't accept the authorisation token in this code:

- (BOOL)canAuthorize {

  NSString *token = self.refreshToken;

  if (token == nil) {

    // For services which do not support refresh tokens, we'll just check

    // the access token.

    token = self.authorizationToken;

  }

  BOOL canAuth = [token length] > 0;

  return canAuth;

}

If self.refreshToken is nil, token will get self.authorizationToken which in place is [NSNull null] even though the server is returning an authorization token as a GET param when redirecting to the redirect URI. The GET param nam is "code", is that the problem?


On Monday, March 25, 2013 12:16:13 AM UTC, Aziz Light wrote:

Aziz Light

unread,
Mar 26, 2013, 6:49:48 AM3/26/13
to gtm-o...@googlegroups.com
OK so I delved in the gtm-oauth2 source code and managed to fixed my problem by modifying two lines in the library.

-------------------------------------------------------------------

GTMOAuth2Authentication.m line 647 was:

    if (token == nil) {

I modified it:

    if ([token isKindOfClass:[NSNull class]]) {

-------------------------------------------------------------------

GTMOAuth2Authentication.m line 1167 was:

    if (str) {

I modified it:

      if (![str isKindOfClass:[NSNull class]]) {

-------------------------------------------------------------------

Those changes fixed my problem. I wonder if they could be integrated into the library. What do you think?


On Monday, March 25, 2013 12:16:13 AM UTC, Aziz Light wrote:

Greg Robbins

unread,
Mar 26, 2013, 10:11:15 AM3/26/13
to gtm-o...@googlegroups.com
Turning on http logging will show the network requests and responses.

Access codes and refresh tokens should not be nulls in the server responses.

Aziz Light

unread,
Mar 26, 2013, 11:26:05 AM3/26/13
to gtm-o...@googlegroups.com
I tried to enable Logging, but the log files never get created... I added

[GTMHTTPFetcher setLoggingEnabled:YES];

[GTMHTTPFetcher setLoggingDirectory:@"/Users/aziz/Desktop/"];

in the main view controller but that didn't do anything. I also imported the logging library (obviously)....

What I want to know is why the app crashes when I disable refresh tokens on the server? If I enable them all works fine, but the Ruby on Rails gem (library) that I use disables refresh tokens for a reason.

Aziz Light

unread,
Mar 26, 2013, 11:28:19 AM3/26/13
to gtm-o...@googlegroups.com
Also, I want to know why my changes to the library are bad?


On Monday, March 25, 2013 12:16:13 AM UTC, Aziz Light wrote:

Greg Robbins

unread,
Mar 26, 2013, 12:43:26 PM3/26/13
to gtm-o...@googlegroups.com
iOS is sandboxed so you cannot pick an arbitrary directory for logs. Use the default logs directory, and look in the Xcode console for the path to the directory where the logs are placed.

Server responses for OAuth 2 should not contain nulls, so checking for nulls in the response is not an appropriate approach for the library.

Aziz Light

unread,
Mar 26, 2013, 12:47:00 PM3/26/13
to gtm-o...@googlegroups.com
When I enable (or try to enable) the logs as described in my previous post, whether or not I include the setLoggingDirectory line, I don't get any output in the console...

Greg Robbins

unread,
Mar 26, 2013, 12:51:13 PM3/26/13
to gtm-o...@googlegroups.com
If no log appears, I suppose either the setLoggingEnabled: is not executing, or the project is not compiled with the DEBUG conditional set, or the OAuth 2 sign-in process is not getting as far as exchanging a code for a refresh token.

Aziz Light

unread,
Mar 26, 2013, 1:13:04 PM3/26/13
to gtm-o...@googlegroups.com
OK so the OAuth 2 sign-in process is not getting as far as exchanging a code for a refresh token. I am sure of that. The reason is, that I disabled refresh tokens on the OAuth server. So naturally the refresh token is not there. Now in the canAuthorize: method, there the following condition in an if statement: if (token == nil) {. Now this condition IS NEVER MET because token (the refresh token in other words) is never nil, it's [NSNull null]. And that's completely normal since I disabled refresh tokens on the OAuth server. So I believe that my changes to the library ARE relevant, or some other changes should be done somewhere else, but the point is: there is nothing wrong with my OAuth server.

Thomas Van Lenten

unread,
Mar 26, 2013, 1:22:22 PM3/26/13
to gtm-o...@googlegroups.com
Where is the NSNull coming from? if the server doesn't do refresh, I'd expect to end up with a nil for the refresh token, not an NSNull.


--
You received this message because you are subscribed to the Google Groups "GTM OAuth 2 Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gtm-oauth2+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Aziz Light

unread,
Mar 26, 2013, 1:28:27 PM3/26/13
to gtm-o...@googlegroups.com
Good question. I don't know the answer, but that's what I get and the only fix that I found was to change the library the way I changed it. A good compromise would be this condition:

if (token == nil || [token isKindOfClass:[NSNull class]]) { ...

That's the only thing I can think of. I would love to find a solution where I don't have to change the gtm-oauth2 library but that didn't happen yet....

Thomas Van Lenten

unread,
Mar 26, 2013, 1:28:57 PM3/26/13
to gtm-o...@googlegroups.com
Do you have a trace of the initial auth?  Is the server sending back a JSON reply or an URL Arg encoded block?

Thomas Van Lenten

unread,
Mar 26, 2013, 1:37:07 PM3/26/13
to gtm-o...@googlegroups.com
On Tue, Mar 26, 2013 at 1:28 PM, Aziz Light <aziiz...@gmail.com> wrote:
Good question. I don't know the answer, but that's what I get and the only fix that I found was to change the library the way I changed it. A good compromise would be this condition:

if (token == nil || [token isKindOfClass:[NSNull class]]) { ...

That's the only thing I can think of. I would love to find a solution where I don't have to change the gtm-oauth2 library but that didn't happen yet....

At this point it's not clear this is a general problem or something specific to the calling code or a specific server.  So it's sorta hard to say the core library should be changed.

The JSON reply code path is one I can see as a possibility where we might get an NSNull back.  Normally, I'd simply expect the server to leave out the key (the refresh token), but since JSON (unlike url argument packing) has the concept of NULL, I can sorta see how this might be done.

You mentioned you disabled the refresh token on the server, how?  Is that a server side change where you might be forcing the null into the reply instead of simply removing the refresh token?

TVL

Aziz Light

unread,
Mar 26, 2013, 2:12:33 PM3/26/13
to gtm-o...@googlegroups.com
My main app is built on Ruby on Rails. I turned it into an OAuth 2.0 provider using a gem/library called Doorkeeper. By default, Doorkeeper doesn't enable refresh tokens. I just didn't enable the refresh tokens.

Greg Robbins

unread,
Mar 26, 2013, 4:18:58 PM3/26/13
to gtm-o...@googlegroups.com
Set breakpoints in GTMOAuth2SignIn at requestRedirectedToRequest: and in GTMOAuth2Authentication at beginTokenFetchWithDelegate:didFinishSelector: and tokenFetcher:finishedWithData:error: as those methods are where most of the action happens. Single-stepping through them should explain much of the implementation of the gtm-oauth2 code.

Incidentally, refresh tokens are an important aspect of OAuth 2 security. OAuth 2 relies on bearer tokens, and transmitting long-lived bearer tokens opens a big attack window. I would not encourage deployment of an OAuth 2 implementation without refresh tokens.

Aziz Light

unread,
Mar 26, 2013, 5:43:17 PM3/26/13
to gtm-o...@googlegroups.com
OK I finally found what was wrong! It's a bug in Doorkeeper, so nothing wrong with gtm-oauth2. Basically, whether or not refresh tokens are enabled on the OAuth server, Doorkeeper includes the refresh token json property, which is null, in the response, and consequently the refresh token received on the Objective-C/iOS side is [NSNull null] instead of nil.

Sorry for trying to change the library even though it wasn't necessary...

Thanks a lot everybody, and a special thanks for your patience!

Aziz Light
Reply all
Reply to author
Forward
0 new messages