Posted: 24 May 2017 8:58 EDT Last activity: 12 Jun 2017 8:53 EDT
Allow deeper configuration of Mashup SDK for iOS behavior
The interfaces provided by your Mashup SDK for iOS are limited, and restrict the use cases where it can be used in apps.
We would like to be able to configure a custom WKProcessPool object in the WKWebViewConfiguration of the PMSnapStartViewController's embedded WKWebView, in order to keep existing cookies. This is not currently possible as the view containing the WKWebView is constructed internally and no variables are exposed through the interface.
One of the two WKWebView initializers can accept an optional configuration parameters of type WKWebViewConfiguration. Please expose some way to configure it from app code using your Mashup SDK, or provide the code from your SDK so that we can modify it on our own.
Our goal was to make API as simple as possible. And we thought that enabling programmer to provide/changing existing WKWebViewConfiguration instance may make more harm than good. But if it will eventually turn out that it is really only way - we will do it.
May I ask you first to elaborate more on what you want to achieve? The WKWebView instances which are created inside PMSnapStartViewController already use shared WKProcessPool instance (it is available as a PMHybridWebView.sharedProcessPool instance). So cookies are shared between these WKWebView instances.
Why do you mean by saying "in order to keep existing cookies". You want to persist session cookies between application launches?
I don't know how to achieve it by using custom WKProcessPool instance. The WKProcessPool instance is just a token, so serializing and deserializing should not restore sessions.
I think you should go with 'HTTPCookieStorage.shared' instance to retrieve/restore your session cookies. I know that cookie synchronization is major problem with WKWebView (WKWebView works in its own process), but in Mashup library we made an effort to workaround these deficiencies to some degree:
- all cookies received via page navigation are immediately put to shared HTTPCookieStorage instance
- Unfortunately cookies obtained via XHR calls are not guaranteed to be put into shared HTTPCookieStorage instance immediately.
- Mashup library is listening for 'NSHTTPCookieManagerCookiesChanged' notifications and tries to update cookie storage on the WKWebView side by invoking some 'document.cookie=..' JS calls.
You can try also to retrieve cookies through 'fetchDataRecordsOfTypes:completionHandler:' method call on one of the WKWebsiteDataStore instances. But I didn't try this.
Thanks for your answer! It's great to be able to talk with someone who worked on the SDK first-hand.
Here is the context: Pega is not used directly for user login, another piece of software sits in front of it in order to handle authentication and account creation using the OpenID standard. This software is KeyCloak.
What I'm trying to achieve is this:
open the KeyCloak URL in my own WKWebView in my app, and make the user log in with is username and password
this will yield session cookies that are stored inside the WKWebView (more precisely inside the WKProcessPool which is part of the WKWebViewConfiguration)
I intercept the redirect to the Pega page as I now want to use the Mashup SDK instead of handling the hybridation in the app myself
I create a PMSnapStartViewController and show it. That's the step where I want to inject the WKWebViewConfiguration (containing the WKProcessPool) that was used by the previous WKWebView I managed myself, in the hope that the cookies used in my own WKWebView will be reused by the WKWebView instantiated within your Pega Mashup SDK
I would also like to store the cookies between app launches, so that the end-user does not have to login in every time he launches the app
Does that clarify your understanding of the context? Do you now understand why I'd like to pass an existing WKWebViewConfiguration instance to the WKWebViews instantiated by the Mashup SDK: it's to share cookies from some preliminary authentication process before calling the Mashup SDK.
As far as the various suggestions you made, here's what I've managed to check at the moment:
WKWebsiteDataStore does not yield cookies, it's just a way to manage the data stored by navigation in a WKWebView. You can for example delete cookies associated with a domain, but you cannot peek inside and read cookie information. So fetchDataRecordsOfTypes:completionHandler is not a solution
As I understand it, if I manage to insert cookies regarding KeyCloak auth inside the shared HTTPCookieStorage, they will be synchronized inside the WKWebView instantiated by the Mashup SDK. The problem here is that these cookies are obviously sensitive for security and are flagged HTTPOnly, so I don't think I'll be able to read them from native code. I will try to use the old UIWebView for my own webview to perform the user login, and see if the cookies generated by it can be inserted inside the share HTTPCookieStorage
Do you think you could send me a modified version of your Mashup SDK with the ability to provide an existing WKWebViewConfiguration to check if this solve this issue?
I went forward and tried a few things. I managed to go further but I'm hitting a blocking crash in the Mashup SDK.
I did change the WKWebView I used in my own code to an UIWebView for loading the KeyCloak auth URL. Upon successful authentication, I now manage to see the private auth cookies (including the JSESSIONID cookie I think is key here) shared inside the shared HTTPCookieStorage.
These cookies seem to be properly synchronized with the WKWebView instantiated by the Mashup SDK. So now when I perform a new OpenHarness action on the PMSnapStartVC, I do not see the Pega login page anymore. I can see using my proxy that the Pega SDK performs a request and receives a response containing an HTML page (see attached screenshots).
However, the Mashup SDK crashes (see attached Xcode screenshots) without any specific information, on a PMOpenURLPlugin Objective-C class. Can you please help us resolve this issue?
I want to underline that we do not use the PMPegaAuthenticator at all in our process, since we already perform authentication externally (using the UIWebView on a KeyCloak page) and pass the cookies to the WKWebView instantiated by the Mashup SDK through the shared HTTPCookieStorage. Could this be cause by the SDK expecting some object that would be set by the PMPegaAuthenticator?
Could you please take a look asap and help us resolve this issue? It's blocking us.
Sorry for late reply. I didn't receive any notification for your response and I missed it.
I understand what you want to achieve and have some questions.
Regarding your first post:
- WKProcessPool. You may want to configure your 'log-in' WKWebView instance with our PMHybridWebView.sharedProcessPool instance? Or event better would be to use PMHybridWebView class for it (it is our wrapper around WKWebView, and it is configured with our WKProcessPool instance OOTB). This will ensure that cookies are synchronized among all WKWebView instances and webview embeded into PMSnapStartViewController will have an access to a session cookie.
- I asked our Product Manager to give me permission to create a custom build for you with configurable WKWebView inside SnapStartViewController. One important question - which version of Mashup SDK are you using? 7.22.5?
- You are right about WKWebsiteDataStore. This is not a way to get an access to WKWebView cookie store. The API for cookie management in WKWebView will be available only since iOS 11. So sorry, for wrong advice.
- Implementing single-sign-on functionality using WKWebView instances is troublesome - to say at least. This is because we don't have programmatical access to WKWebView cookie storage. If you are interested I may describe later how we have achieved SSO in our Hybrid Container application (iOS/Android app built on Mashup SDK which opens PRPC application).
- I don't understand your point regarding HttpOnly cookies. Such cookies are of course accessible from native code. The 'HttpOnly' flag means that these cookies are not accessible (you cannot read them or modify) from JS, for example from document.cookie API.
- Regarding old UIWebView. It runs in the same process as the rest of application and all cookies obtained by UIWebView are immediately put to shared NSHTTPCookieStorage and vice versa.
- I am afraid that there is no guarantee that after obtaining session cookies via UIWebView they will be always immediately synchronized with WKWebView instances. I would rather try to use PMHybridWebView instead of UIWebView.
- JSESSIONID and Pega-RULES are the important session cookies here.
- Using PMPegaAuthenticator is not obligatory. Definitely it is not a cause of your crash.
- From screenshots you attached I see that most probably that application has crashed because of a call to [PMApplicationDelegate sharedInstance] in [PMOpenURLPlugin didCallOnLaunchboxLoaded] method. It looks like PMApplicationDelegate singleton doesn't exist. Make sure that your AppDelegate:
1) Extends from PMApplicationDelegate
2) or (if your AppDelegate already extends from something else) creates a single instance of it using default constructor. And then your AppDelegate has to pass all application events to PMApplicationDelegate instance - it implements all UIApplicationDelegate methods.
Thanks for the additional information, including the list of important session cookies. That's what I had inferred from looking at the behavior of the login process.
I am using version 22.214.171.124 of your Mashup SDK.
I understand the limits of the synchronization between the UIWebView and the WKWebView, I did not notice any delay yet. I did not know however that the SDK provided the PMHybridView and that it was aimed at a scenario similar to the one I am investigating. I will work on this later instead of using the UIWebView.
I changed my code to inherit from PMApplicationDelegate instead of UIApplicationDelegate. It is not properly autocompleted by Xcode and there are all sorts of warnings and errors that crop-up when using it even though the app still builds and runs regardless.
Now the app does not crash anymore when opening a harness, thanks! However, when opening that harness, I simply see the homepage in the Mashup SDK WKWebView: shouldn't it display a more specific page? I don't know the specifics of Pega yet so I don't know if it's normal or if I should try to call a Create Case action instead.
I just tried the Create Case action instead of Open Harness and I receive a Pega error page, stating:
"The operation completed successfully, but returned no content"
[EDIT] Nevermind, I had not specified the flowType and insClass parameters. I did and it now shows the new case page.
Thank you very much for your help. From my point of view, I validated the usage of external authentication (KeyCloak) along the Mashup SDK, but there are still details to be fixed to make it work for an actual app.
The SnapStartViewController is intended to execute some predefined actions in your PRPC application like:
- creating new case instance
- opening already existing case instance
- opening a specific assignment or a harness
- running an activity on server side
So these API allows you to quickly open a webview with your PRPC application in a specific context. So user will not have to make any unnecessary clicks from main portal to a specific case type/harness in your app.
Once user submits or closes his case the 'complete' method will be invoked on a delegate object. And it would be a good moment to dismiss SnapStartViewController instance from app UI.
On the other hand, if you want to just open your PRPC application just like it happens on a desktop (main portal visible on start) please just load NSURLRequest with url pointing your PRPC instance into PMHybridWebView instance. Of course I am still assuming that before this you obtained session cookies in other webview.