GCM 3.0: New registration does not expire tokens registered with GCMRegistrar - google-cloud-messaging

We are switching our notifications infrastructure to use new GCM 3.0 registration mechanism using Instance ID API. Previously we were using old mechanism using GCMRegistrar.register() method.
The problem we have is that we have noticed that if device was registered with old GCMRegistrar, after update and registering with new Instance ID API, both registration tokens are valid and can receive notifications.
I expected old registration token to be deactivated and that our push server would receive canonical registration ID when sending notification to old token (as described here GCM registering with two different working registration ids), especially that application version has changed, but such case seems not to happen.
Is this correct behavior of GCM? Is there any way we can detect on push server that device received new token (without unregistering from app)?

I have finally received an answer from Google support regarding my issue. It turned out that this was intended behavior:
What you observed is in the intended behavior due to the need to support backward compatible
registration ID.
We recommend you to flag the old registration ID from gcmregistrar() and don't use that to send anymore once you have the registration token from getToken(). (I believe you probably has implemented a solution to detect such)
Our solution was to simply remove old registration tokens from our push server before registering new user.
We did not use GCMRegistrar.unregister() as we observed that it was able to unregister new tokens (obtained via getToken()).
UPDATE:
I just wanted to provide a quick update to anyone interested in this subject.
It seems that this issue was fixed as when we tested our registration mechanism recently, it turned out that new GCM tokens replace (and unregister) old tokens.

Registration token may change upon certain scenarios even going forward. While cononical registration ID is also a good idea. Use tokenRefresh as shown here as well.
#Override
public void onTokenRefresh() {
// Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
Suggesting based on this line "it is needed for key rotation and to handle special cases" in method reference.

Related

Vertx Sockjs Eventbus handler authorization

Im building a social platform and just started on the websocket portion. I'm having trouble understanding where to hook my auth into the Vert.x SockJsHandler. I found a code example using "SockJsServer" via vertx.createSockJsServer here but it doesnt seem like that exists in current versions:
https://github.com/michalboska/codingbeer-vertx/blob/auth-experiment/src/main/java/ch/erni/beer/vertx/HTTPServerVerticle.java
The only hook Im aware of in current version is:
return SockJSHandler.create(vertx).bridge(options) {event ->
logger.info{ "socket event: ${event.type()}" }
event.complete(true)
}
I see event.socket().webUser() and .webSession() exists but am unclear how/where that would get set. So my question is, will I need to create an auth handler on the initial handshake only and if so, where? If a js client needs to receive notifications for say, a message from a specific chatroom they are a member 'chat123', should I register unique handlers for chat123, or somehow iterate over event.socket().webUser() for valid ids each time?
Most vert.x docs are offline with the new site migrating to vert.x 4 so infos a bit hard to find at the moment.

Slack API remove bot from channel

I'd like to remove a slack bot from a channel using slack's API.
I've tried channels.kick but ofcourse, a bot is not a user so it can't be deleted that way. I haven't found any solutions so far on the interwet or on Slacks API documentation.
You are not correct. You can remove a bot user from a public channel or private channel using API methods just fine. I just tested it on a private channel to confirm.
So there must be another reason why this does not work for you. Please check if any of these reasons below apply to your case. Also, please provide the error message you are getting from the API, as that would greatly help to identify the reason.
Here are some potential reasons why kicking a bot user might not work for you:
wrong method: channels.kick only works for public channel, use groups.kick for private channels.
wrong token: bot tokens can not use the kick methods. You need to use a user access token to invoke that API method. (you would get the user_is_bot error)
trying to remove oneself: a user can not kick himself. (you would get the cant_kick_self error)
not using channel IDs: the kick methods require you to provide a channel ID, the name will not work. (you would get the channel_not_found error)
Based on your question I would assume you are getting the user_is_bot error, which let you to assume (incorrectly) that you can't kick a bot. In that case the solution would be to use a user token (not a bot token) to execute the method.

GoogleTokenResponse.getIdToken() returns null

Our server OAuth validation via Google has started throwing NullPointerException within GoogleTokenResponse.parseIdToken():
java.lang.NullPointerException:
at com.google.api.client.json.webtoken.JsonWebSignature$Parser.parse(JsonWebSignature.java:462)
at com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.parse(GoogleIdToken.java:57)
at com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse.parseIdToken(GoogleTokenResponse.java:106)
This is new behavior that started today. There was no change to our server code (it has worked for months). The problem occurs only with credentials from one Android device -- I have another that works fine. Refreshing the client's server access token does not solve the problem.
The GoogleTokenResponse is being created by GoogleAuthorizationCodeTokenRequest(), that call succeeds and when I log the GoogleTokenResponse it looks valid:
{"access_token":"ya29.mwJvM...","expires_in":3600,"token_type":"Bearer"}
UPDATE: tested some more and found tokenResponse.getIdToken() is returning null, so I assume that's what's causing the NPE when I call parseIdToken().
What would cause getIdToken() to return null when GoogleAuthorizationCodeTokenRequest() apparently succeeded and there is an access token?
Final resolution: this issue appears to be triggered intermittently by the Google Play Services update in early 2016 to anonymize PlayerID. We were able to fix our problems by changing our server validation of the access token to a newer method instead of relying on the older getIdToken()/parseIdToken() methods. See the last UPDATE below for details
After two days the Android device with this failure mysteriously started to work again. So the cause may be a transient error in the client's Google Play Services state which self-corrected. The fix occurred after a device reboot.
However I'm not certain that was the cause. There are also Play Services changes rolling out to enable authentication without exposing the G+ user ID -- another explanation is the server was not being given scope to retrieve the ID. (If that was the cause, then again the fix must have been deployed by Google as we have not changed anything)
We'll continue to monitor it, if anyone else runs into this add a comment please.
4/19/16 This problem has occurred on a different device. I am wondering if this is related to the Google Play auth changes described here http://android-developers.blogspot.com/2016/01/play-games-permissions-are-changing-in.html?m=1
That explanation is a bit sparse but it does say "The user_id returned by token info may no longer be present with the new model. And even if it is present, the value won’t be the same as the new player ID"
In this case the problem occurred after
Device had previously authorized with Google Play Services in the old G+-style
App data was cleared so re-auth was necessary
During re-auth GPS prompted for the new GPS-only player ID (not real name), which makes me wonder if it switched that device to the new non-G+ ID
Then server calls to tokenResponse.getIdToken() returned null
I'm not yet sure what's happening but researching two areas of concern:
1) Although the Google docs referenced above say "existing players ... will continue to get their Google+ ID" I'm wondering if this is managed per-client. That would be a big problem because we use that ID to store cloud state for a user across devices, so if a user who originally set up their account before the new player ID then installed the app on a second device, they could sign in with gplay but the two accounts would not match
2) If this is the cause, then either our server code fails to work with the new non-G+ player ID, or there is a google back-end bug when a device transitions between the two. This is still confusing though because our prior problem did self-correct after a couple of days, which implies the server code is fine -- but I'm sure hoping the alternate explanation of a bug with google back-end auth is wrong!
--- UPDATE
I think the issue is related to the new GPS anonymized PlayerID changes. It has been hard to debug because it appears that Google's legacy server auth flow, which requires a non-null GoogleTokenResponse.getIdToken(), fails for a newly created GPS PlayerID, but after 12-24 h the problem seems to self-correct and the legacy Google auth calls begin to succeed including returning a non-null getIdToken().
However I tried implementing the new PlayerID flow in the Step 7 of the google info page above which converts the access token (generated from a server auth code) to a Player ID via www.googleapis.com/games/v1/applications//verify/
This code successfully retrieves a Player ID from the accessToken even when getToken() returns null:
// URL: www.googleapis.com/games/v1/applications/<app_id>/verify/
URL url = new URL("https://www.googleapis.com/games/v1/applications/" + GPlayServicesAppId + "/verify/");
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setRequestProperty("Authorization", "OAuth " + accessToken);
httpConnection.setRequestMethod("GET");
int responseCode = httpConnection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
...
}
BufferedReader reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
String responseJson = (read contents of reader)
// Example response: { "kind": "games#applicationVerifyResponse", "player_id": "11520..."}
I ran some tests, far as I can tell the new method works in all cases where the older G+ getToken() method works as well as fixing the cases where it doesn't, so I believe we can just switch to the new method in the code snippet above and hopefully that will be reliable.

IBM Worklight 6.1.0.1, trouble with 2 adapters based authentication

I am facing to a trouble with 2 adapters based authentication. My app is agenda (hybrid app). All adapter's functions must be protected by security.
my app uses adapters based authentication, like written in samples on DeveloperWorks.
My first adapter (loginAdapter) is dedicated for login (beginning of the mobile app). I developed a handler (handlerLogin, mobile side) with methods isCustomResponse, handlechallenge, etc.. This adapter works.
This adapter allows to get a userId from login and password.
As soon as connected, the user can download his agenda. The mobile calls an other adapter based auth (calendarAdapter). I have an other handler (handlerCalendar) with methods (isCustomResponse, handlechallenge).
When the mobile calls the method getCalendarData (protected method, CalendarAdapter), the server detects that the user is not registered for this adapter, that is why the server send an error (structure authrequired + errorMessage) via the function onAuthRequired.
At this step, all works fine.
Actually, the trouble comes from, that, the first handler (handlerLogin) catches this error, whereas it schould be the second handler (handlerCalendar).
Given that it is catched by the handlerLogin, isCustomResponse and handlechallenge are called, and I do not have the expected result ! I do not know why.
Why it is not catched by the handlerCalendar ?
I verified my code, variable's names, files, etc.. All things are ok.
For informations, I first declared the handlerLogin before the CalendarLogin.
Do you have any ideas, suggestions ??
Thank you in advance
It looks like you used the same realm.
The isCustomResponse function job is to find out if this challenge-handler should take care of this specific request. If you use the same realm for both adapters then the 2 challenge-handlers will react to it.

IBM Worklight: Extend Server-side Java Code

Can I extend the server-side Java Code in Worklight?
For example, there is a class called JavaScriptIntegrationLibraryImplementation under com.worklight.integration.js. Inside this class, there is a method broadcastNotification and I would like to override this method. Is it possible to do so?
EDIT
The reason is that:
When I make the subscription in client side with option field (e.g. add customType: A), I would like to retrieve a list of devices which have been subscribed to this event source. Base on the option field in deviceSubscrpition, I would like to have some business logic to determine who to send the notification message. For example, I will only submit the message to the user which 'customType=A'.
However, there is no API in Worklight which can retrieve a list of devices which make me to retrieve the list first. Then do the logic in JavaScript and called WL.Server.notifyDevice..
Therefore, I would like to check whether there is any method to retrieve a list of devices (through API / Adapter which connects to DB) which have subscribed to an event source.
Thanks.
This part of Worklight is not extendable. You can try and override this method as you say, but do note this is not supported and we cannot help in this case.
Edit
Now that it is clear what you're trying to achieve... what you are looking for currently not available. I will open a feature request for it and it will get evaluated at some point (if you are a customer of IBM, I suggest to get in touch with your contact...).
My suggestion (somewhat hackish in form): you could perhaps use multiple Event Sources, where each event source represents an iOS version. On the client-side, upon app initialization, you can retrieve the iOS version and use it to register to the correct event source (this would be very generic code to allow re-use). In case a new iOS version is released (you will likely know of this in advance), you simply add this event source to the adapter code and re-deploy the adapter. Users of the new iOS version could still register for notification, because you get the iOS version upon init, and use this information to register to the correct event source...
To reiterate:
The adapter contains: ES_iOS5 ES_iOS6
The client:
fetches iOS version, stores it in some variable.
registers to event source, where event source name is ES_${iOSVersion}
if a new iOS version is released, simply create a new event source and re-deploy
the adapter; the client is already equipped to handle this.
#Red23jordon,
i had similar case, i created a custom table where at the time of subscription, I was saving
user ID and event type in custom table. and when user unsubscribe then i also remove details from custom table.
For sending push to users subscribed to a particular "even type" i look into custom table to get list of user IDs subscribed to particular event type, and then i went into Notification user/device tables and fetching corresponding devices and sending Push.
Hope it may help you.
thanks