RE: WebScreenlet Session for Device registration for Android Push notificat

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Hi All,

 

I am developing an app with Liferay web screenlet for rendering web pages in Android app. Now If I have to implement push notification in this app. How can I register device for users?

For other screenlets, I did device registration after Login using LoginListener. How can I do the same in WebScreenlet?

I want device to be registered, once user logged in portal using Web screenlet.

 

Thanks,
Ankit

thumbnail
Sarai Diaz, modified 7 Years ago. New Member Posts: 23 Join Date: 6/14/16 Recent Posts

Hello Ankit,

You can create a JavaScript file with the logic (when the user is logged in the application) and inject it in the WebScreenlet. Then, you can control whatever you want in this method:

public void onScriptMessageHandler(String namespace, String body)

 

Regards,

Sarai

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks Sarai for your reply.

Where can I write this javascript and will I able to get Liferay objects like themeDisplay inside? Do you have any example code?

It seems SessionContext also will not work in case of WebScreenlets.

 

Regards,

Ankit

 

thumbnail
Sarai Diaz, modified 7 Years ago. New Member Posts: 23 Join Date: 6/14/16 Recent Posts

You can add a JavaScript file from three different sources: locally,  remotely or from Android Studio raw folder.

Please see the documentation: https://dev.liferay.com/develop/reference/-/knowledge_base/7-0/web-screenlet-for-android#configuration

Inside your JavaScript file you can access Screens object, to post a message from JavaScript to native and do whatever you want inside the method I mentioned in the previous reply. Also, in the JavaScript file you can access themeDisplay to check userId or other properties.

 

Regards,

Sarai

 

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks Sarai.

I was able to get userId from themeDisplay in my javascript and then I was able to post it app:

window.Screens.postMessage('userId', userId);

But now for registering device, we need to have Session object as per below API:

Push.with(session).register(this, YOUR_SENDER_ID);

Do we have any API to get session in WebScreenLet or session from userId? as below API will not work in my case:

Session session = new SessionImpl(YOUR_SERVER, new BasicAuthentication(YOUR_USER, YOUR_PASSWORD));

and

Push.with(SessionContext.createSessionFromCurrentSession()).register(this, YOUR_SENDER_ID);

Thanks,

Ankit

thumbnail
Sarai Diaz, modified 7 Years ago. New Member Posts: 23 Join Date: 6/14/16 Recent Posts

You can use UserConnector to get the user from its userId: https://github.com/liferay/liferay-screens/blob/develop/android/library/src/main/java/com/liferay/mobile/screens/auth/login/connector/UserConnector.java

And then, create the session with the username and password.

Hope it helps.

Regards,

Sarai

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

I can get user and create session in case of basic authentication for portal users  but in our case we are using SAML authentication and Identity provider is ADFS.

In our case, password is being managed at ADFS side. So how will we able to create session by passing username and password?

 

And also to access UserConnector object, we will require session object :

https://github.com/liferay/liferay-screens/blob/develop/android/library/src/main/java/com/liferay/mobile/screens/auth/login/connector/UserConnector62.java

 

Regards,

Ankit

thumbnail
Javier Gamarra, modified 7 Years ago. Expert Posts: 348 Join Date: 2/12/15 Recent Posts

Yep, I see... you don't have a lot of options.

 

You can either capture the user/password with a WebView when they login against ADFS (fragile and insecure), use CookieAuthentication in the session and hope that the cookie is valid for the portal or configure another, preferably token-based authentication method (complementary with SAML) or disable authentication for that endpoint (or adding a filter to authenticate based on other information)... I think that is all :(

 

The best way would be decoupling the userId needed for push with the authentication needed for the request, that way you could use a default user created just for registering users in the portal (with just those permissions). It would have several inconveniences (it can be leaked, but at least you can invalid it, you have to hardcode something...). If you want to follow this approach we can help you modifying the code.

 

Maybe @VictorGalan can shed more light about disabling/changing security in that endpoint. Pinging him internally.

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks for your response Javier.

"The best way would be decoupling the userId needed for push with the authentication needed for the request, that way you could use a default user created just for registering users in the portal (with just those permissions). It would have several inconveniences (it can be leaked, but at least you can invalid it, you have to hardcode something...). If you want to follow this approach we can help you modifying the code."

 

Do you mean to say for registering device, I should use a default user rather than using actual user who owns the device? How will we implement Role based notification then? or you mean to say create one default user for each role and then while registering device, check role of actual user and register device with default user of same role?

We are having users with different roles and notification will be send to set of users having specific role  for specific case.

 

Thanks,

Ankit

 

thumbnail
Javier Gamarra, modified 7 Years ago. Expert Posts: 348 Join Date: 2/12/15 Recent Posts

Yes, I mean using a default user just for calling the json ws services and passing the userId as one of the arguments. You could check the role of the userId or the permissions inside the service. You would have to modify a small part of the mobile client (we can help with that) and add a hook/code in the portal. 

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

So If I am understanding it correctly, first I have to call RoleService by passing default user authentication and then by passing actual userId, need to identify its role. 

       Session session = new SessionImpl("http://xyz.com", new BasicAuthentication("test","test"));
       RoleService roleService = new RoleService(session);
       JSONArray roleList = new JSONArray();
       try {
           roleList = roleService.getUserRoles(Long.parseLong(actualUser));
           Log.i(TAG, "Role List"+roleList);
        } catch (Exception e) {
            e.printStackTrace();
         }

Once we get role of actual user (SAML user), We need to create session using default user with same role as actual user. There will be lot of if/else conditions to achieve that and also not sure, if exposing these many credentials in code is correct or not (We have 10 roles). 

"You would have to modify a small part of the mobile client (we can help with that) and add a hook/code in the portal. "

Thanks, please suggest.

 

Regards,

Ankit

thumbnail
Javier Gamarra, modified 7 Years ago. Expert Posts: 348 Join Date: 2/12/15 Recent Posts

If you just want to register a role, instead of a user, yes. But, if I understand correctly, that's not what you want, you need to send notifications to a specific users (but with a logic based on the role).

 

The idea would be doing the same request but also sending the userId (and do the role logic on the server). We would have to modify the push library.

 

But talking with Víctor... he has recommended the cookie approach... does it work for you?

 

You can capture a valid cookie to do a login/push request with CookieManager.sync().getCookie(url) and capture the authToken through javascript in the webview. With that you can create a valid CookieAuthentication and pass that do the push service and will be a valid authentication to that user.

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

HI Javier,

If you just want to register a role, instead of a user, yes. But, if I understand correctly, that's not what you want, you need to send notifications to a specific users (but with a logic based on the role).

As per my understanding, device registration is speific to user not with role. So initially every user of my portal, who has installed app and logged in, will get his device registered for Push Notifications and then while sending notification, we will be having role based notifications, so will be sending notification to al users under that role. My Challenge is to register device with user.

The idea would be doing the same request but also sending the userId (and do the role logic on the server). We would have to modify the push library.

Yes, this is what I shared in my last post. I got the loggedin userId from WebScreenLet javascript (OnScriptMessageHandler) but cannot do much with this userId.

My Challenge is to create Session for device registration. I called UserConnector as per your suggestion by using admin/default user session but then stuck as it will not help me to create session for logged in user. 

I also called RoleService using default/admin user to get role of logged in user but then also cannot get Session to register device. As per last suggestion if I create default user for each role and pass it to make session, I will be exposing lot of users credentials. My question was, if it ok to do that?

But talking with Víctor... he has recommended the cookie approach... does it work for you?

You can capture a valid cookie to do a login/push request with CookieManager.sync().getCookie(url) and capture the authToken through javascript in the webview. With that you can create a valid CookieAuthentication and pass that do the push service and will be a valid authentication to that user.

Even in above approach, I will be requiring user's password to create session. Do you have working example for this? 

 

Regards,

Ankit

 

 

 

 

thumbnail
Javier Gamarra, modified 7 Years ago. Expert Posts: 348 Join Date: 2/12/15 Recent Posts

As per my understanding, device registration is speific to user not with role. So initially every user of my portal, who has installed app and logged in, will get his device registered for Push Notifications and then while sending notification, we will be having role based notifications, so will be sending notification to al users under that role. My Challenge is to register device with user.

 -> Yes, everything is correct.

Yes, this is what I shared in my last post. I got the loggedin userId from WebScreenLet javascript (OnScriptMessageHandler) but cannot do much with this userId.

My Challenge is to create Session for device registration. I called UserConnector as per your suggestion by using admin/default user session but then stuck as it will not help me to create session for logged in user. 

I also called RoleService using default/admin user to get role of logged in user but then also cannot get Session to register device. As per last suggestion if I create default user for each role and pass it to make session, I will be exposing lot of users credentials. My question was, if it ok to do that?

-> It would be Ok. But you would have to modify several things. Cookie Auth, explained below is better :)

Even in above approach, I will be requiring user's password to create session. Do you have working example for this? 

-> That's what I didn't explain correctly. There is a method to create the session with the Cookie (and another for OAuth or token auth). You can create a Session with new SessionImpl(IP, new BasicAuthentication()) but also with new CookieAuthentication and that class it doesn't need the user and password, just things that you can capture in the WebView.

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks Javier,

I was following approach suggested by you and wanted to get cookies from portal and then post it to webscreenlet using onScriptMessageHandler.

But when I tried getting cookies at portal side using document.cookie, It does not provide httpcookie. For example, JSESSIONID, SAML_SP_SESSION_KEY etc are not availble in list fetched. How can I retrieve all cookies and create Session (using CookieAuthentication) with those cookies without username and password?

 

Regards,

Ankit

thumbnail
Victor Galan, modified 7 Years ago. Regular Member Posts: 144 Join Date: 6/14/16 Recent Posts

Hey!

 

You need to get the cookies from the Webview itself, using android classes. Let me try to explain the whole process:

 

- First, you load the webscreenlet with your page as you are doing

- You have to detect when you have logged in the webview. Implement weblistener a check it in the OnPageLoaded method.

- Once you are logged, you have to execute a script in the webView to grab the authToken. For doing this you have to create a Script a inject it:

JsScript script = new JsScript("session", "window.Screens.postMessage('token', Liferay.authToken);");

webScreenlet.injectScript(script);

This script will take the authToken and send it to the native part. You will receive it in the OnScriptMessageHandler listener method.

- Now, after receiving the authToken, you will have to get the cookies:

String cookieHeader = CookieManager.getInstance().getCookie(<url-of-your-server>);

With this two things you can create an ephemeral authentication:

CookieAuthentication cookieAuthentication = new CookieAuthentication(authToken, cookieHeader, "", "", false, 0, 0);

- With this authentication you can create a session

Session session = new SessionImpl("http://screens.liferay.org.es", cookieAuthentication);

- Lastly, you can use this session to register the device:

Push.with(session).register(this, YOUR_SENDER_ID);

 

You have a project with a working example  here it is calling an arbitrary jsonws service, but it will work with all of them.

I hope it helps

 

Regards

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks Victor for detailed explanation with example.  I will try it and update you.

 

Regards,

Ankit

thumbnail
Ankit Srivastava, modified 7 Years ago. New Member Posts: 12 Join Date: 1/5/18 Recent Posts

Thanks for your help Victor. I am able to register the device with above approach and also push notifications are working fine.

 

Regards,

Ankit