invoke adapter from PHP script - ibm-mobilefirst

I am sending push notification to all devices and for that i have created adapter for tag based push notification as follows.
function sendTagNotification(applicationId, notificationText, notificationTags) {
var notificationOptions = {};
notificationOptions.message = {};
notificationOptions.target = {};
var tags = notificationTags.split(",");
notificationOptions.message.alert = notificationText;
notificationOptions.target.tagNames = tags;
WL.Server.sendMessage(applicationId, notificationOptions);
return {
result : "Notification sent to users subscribed to the tag(s): '" + notificationTags + "'."
};
}
now the approach we want is , we will be having the php script which will send the message content to Worklight Adapter and sendTagNotification adapter will receive the message content and send it to all mobile users.
so is there any way to invoke adapter from PHP script ?

Assuming you are using MobileFirst 7.0 and above, and your adapter procedure is protected with a security test, you would need to implement what is termed a "confidential client" in order to act as an OAuth client that handles the OAuth challenege: http://www-01.ibm.com/support/knowledgecenter/SSHS8R_7.1.0/com.ibm.worklight.dev.doc/dev/c_non_mobile_to_mobile_services.html
Another way this can be done is to have the PHP script call the adapter procedure URL, but that adapter procedure must be unprotected using securityTest="wl_unprotected". For example using curl, with the parameters in the URL body: curl http://my-host:my-port/project-context-root/adapters/adapter-name/procedure-name
If using MobileFirst 6.3, you can invoke the adapter procedure from the Studio (right-click on the adapter folder and select Run As > Invoke MobileFirst adapter procedure) and enter some details. A browser window will open.
You should be able to copy the URL that will be there and adjust the appended parameters in your script...

Related

Sending a link using push notifications in Azure for Android

I have created a backed in asp.net web-forms successful send a notification for all registered devices but I tired to send a link for example I need to send one push notification include a link When user touch on the notification redirect to mobile browser and open the link.
private static async void SendNotificationAsync()
{
NotificationHubClient hub = NotificationHubClient
.CreateClientFromConnectionString("<Here is my endpoint >", "<hub name>");
await hub.SendGcmNativeNotificationAsync("{ \"data\" : {\"message\":\"Hello Users \"}}");
}
Based on my experience, we could use custom json format and at receiver end convert that string into url. For example,Here’s a sample of the complete JSON payload with a custom "web_link" key containing the URL:
{"data": "{\"message\":\"xxxx\",\"web_link\":\"https://www.example.com\"}"}
Then we could override the OnMessage function to create Notification, we also could get more detail info from the Azure document.

Google OAuth 2.0 for desktop apps for Windows without Admin privileges

I've heard about Google's plan of modernizing OAuth interactions described here: https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html
Then I was looking at the sample desktop application for Windows found here: https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp.
It's pretty simple and it was working, but once I started Visual Studio without elevated privileges (as a non-admin), I experienced that the HttpListener was not able to start because of the following error: "Access Denied".
It turned out that starting an HttpListener at the loopback address (127.0.0.1) is not possible without admin rights. However trying localhost instead of 127.0.0.1 lead to success.
I found that there is a specific command that allows HttpListener to start at the given address (and port):
netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user
But it also can be only executed with admin rights, so it's not an option.
Still localhost seems to be the best shot but OAuth 2.0 for Mobile & Desktop Apps states the following regarding this section:
See the redirect_uri parameter definition for more information about the loopback IP address. It is also possible to use localhost in place of the loopback IP, but this may cause issues with client firewalls. Most, but not all, firewalls allow loopback communication.
This is why I'm a bit suspicious to use localhost. So I'm wondering what is the recommended way of Google in this case, as I'm not intending to run our application as administrator just for this reason.
Any ideas?
You can use TcpListener for instance instead of HttpListener. It does not need elevation to listen.
The following is a modified excerpt of this sample:
https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp
// Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";
// Creates a redirect URI using an available port on the loopback address.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port);
output("redirect URI: " + redirectURI);
// Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
authorizationEndpoint,
System.Uri.EscapeDataString(redirectURI),
clientID,
state,
code_challenge,
code_challenge_method);
// Opens request in the browser.
System.Diagnostics.Process.Start(authorizationRequest);
// Waits for the OAuth authorization response.
var client = await listener.AcceptTcpClientAsync();
// Read response.
var response = ReadString(client);
// Brings this app back to the foreground.
this.Activate();
// Sends an HTTP response to the browser.
WriteStringAsync(client, "<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please close this window and return to the app.</body></html>").ContinueWith(t =>
{
client.Dispose();
listener.Stop();
Console.WriteLine("HTTP server stopped.");
});
// TODO: Check the response here to get the authorization code and verify the code challenge
The read and write methods being:
private string ReadString(TcpClient client)
{
var readBuffer = new byte[client.ReceiveBufferSize];
string fullServerReply = null;
using (var inStream = new MemoryStream())
{
var stream = client.GetStream();
while (stream.DataAvailable)
{
var numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length);
if (numberOfBytesRead <= 0)
break;
inStream.Write(readBuffer, 0, numberOfBytesRead);
}
fullServerReply = Encoding.UTF8.GetString(inStream.ToArray());
}
return fullServerReply;
}
private Task WriteStringAsync(TcpClient client, string str)
{
return Task.Run(() =>
{
using (var writer = new StreamWriter(client.GetStream(), Encoding.UTF8))
{
writer.Write("HTTP/1.0 200 OK");
writer.Write(Environment.NewLine);
writer.Write("Content-Type: text/html; charset=UTF-8");
writer.Write(Environment.NewLine);
writer.Write("Content-Length: " + str.Length);
writer.Write(Environment.NewLine);
writer.Write(Environment.NewLine);
writer.Write(str);
}
});
}
By default there is a URL pattern http://+:80/Temporary_Listen_Addresses/ which is allowed for all users (\Everyone)
You can use this as a prefix for your listener. More generally (to avoid collisions with other listeners) you should generate a URL under Temporary_Listen_Addresses (e.g. using a GUID) and use that as your listener prefix.
Unfortunately, a sysadmin can use netsh http to delete this entry or to restrict its usage to only certain users. Also, this does not appear to support listening for an HTTPS request as there is no corresponding ACL entry for port 443.
An admin can list all these permitted URL patterns using netsh http show urlacl as a command.

Sense/net using content query in web application

I try to use content query in web application but it throw an exception " Lucene.Net.Store.AlreadyClosedException: this IndexReader is closed". Please give help me resolve that problem.
var startSettings = new RepositoryStartSettings
{
Console = Console.Out,
StartLuceneManager = true, // <-- this is necessary
IsWebContext = false,
PluginsPath = AppDomain.CurrentDomain.BaseDirectory,
};
using (Repository.Start(startSettings))
{
var resultQuery = ContentQuery.Query("+InTree:#0 + DisplayName:*#1*", null, folderPath, q);
}
The recommended way to connect to Sense/Net from a different application (app domain) is through the REST API. It is much easier to maintain and involves less configuration (the only exception is where you are working inside the Sense/Net application itself, or you only have a single application and you do not want to access Sense/Net from anywhere else, and you are willing to deal with a local index of Sense/Net and all the config values it needs, etc).
Connecting through the REST API does not mean you have to send HTTP requests manually (although that is also not complicated at all): there is a .Net client library which does that for you. You can access all content metadata or binaries through the client, you can upload files, query content, manage permissions, etc.
// loading a content
dynamic content = await Content.LoadAsync(id);
DateTime date = content.BirthDate;
// querying
var results = await Content.QueryAsync(queryText);
Install: https://www.nuget.org/packages/SenseNet.Client
Source and examples: https://github.com/SenseNet/sn-client-dotnet
To use it in a web application, you have to do the following:
initialize the client context once, at the beginning of the application life cycle (e.g. app start)
if you need to make requests to Sense/Net in the name of the currently logged in user (e.g. because you want to query for documents accessible by her), than you have to create a new ServerContext object for every user with the username/password of that user, and provide this object to any client call (e.g. load or save content methods).
var sc = new ServerContext
{
Url = "http://example.com",
Username = "user1",
Password = "asdf"
};
var content = await Content.LoadAsync(id, sc);

How to connect a worklight app to a datapower backed on the start

We are developing a DataPower(DP) + Worklight(WL) POC
Having this objective in mind, we are following this article: http://www.ibm.com/developerworks/websphere/techjournal/1301_efremenko/1301_efremenko.html
We are clear and on sync with about the DP role on this approach, but we have one question related to the WL code implementation.
At the WL application client code we are using WL HTTP Adapters for all the http requests (REST+JSON) to the backend, like this:
WL.Client.invokeProcedure(invocationData, options);
These adapters are pointing to the DP MPGW endpoint, but based on our understanding, the HTTP Adapter code runs on WL Server.
If it is correct, our assumption for the execution sequence is:
WL Client App -> WL Server -> DP MPGW -> WL Server
When we are looking the same sequence mentioned in the DW article:
WL Client App ->DP MPGW -> WL Server
Could anyone please clarify our understanding about how the WL HTTP Adapter works in this case?
When you're using Worklight Adapter to call DP MPGW, the sequence as below
Request:
WL Client App --> WL Server (Adapter) --> DP MPGW
Response:
DP MPGW --> WL Server (Adapter) --> WL Client App
NOTE: The session id before/after WL server (Adapter) is not the same. If you want to do SSO, you need to pass your LTPA token in adapter to the backend DP. Here's the sample code for you.
Step1. Get LTPA token method (in you ChallengeHandler.js file)
sampleAppRealmChallengeHandler.isCustomResponse = function(response) {
if (!response || response.responseText === null) {
return false;
}
var indicatorIdx = response.responseText.search('j_security_check');
if (indicatorIdx >= 0){
return true;
}else if(response && (response.responseJSON) && (response.responseJSON['WL-Authentication-Success']) && (response.responseJSON['WL-Authentication-Success']['WASLTPARealm'])){
// set ltpaToken when login success
var realm = response.responseJSON['WL-Authentication-Success']['WASLTPARealm'];
ltpaToken = realm.attributes.LtpaToken;
console.log('Get ltpa token success: '+ltpaToken);
}
return false;
};
Step2. Call procedure method (in client App js file)
// define global LTPA token variable
var ltpaToken = null;
function getAccountInfo(){
// check ltpa token is not null, or get the ltap token from login user in WASLTPARealm
if(!ltpaToken){
if(WL.Client.isUserAuthenticated('WASLTPARealm')){
var attrs = WL.Client.getUserInfo('WASLTPARealm', 'attributes');
if(attrs){
ltpaToken = attrs.LtpaToken;
console.log('Set ltpaToken again: '+ltpaToken);
}
}
}
// Pass LTPA token from client App to WL server(adapter)
var token = {'LtpaToken2' : ltpaToken};
var invocationData = {
adapter: "DummyAdapter",
procedure: "getAccountInfo",
parameters: [token]
};
WL.Client.invokeProcedure(invocationData, {
onSuccess: getSecretData_Callback,
onFailure: getSecretData_Callback
});
}
Step3. Pass LTPA token to backend DP in adapter
function getServices( token) {
path = getPath("path/to/services");
var input = {
method : 'post',
returnedContentType : 'json',
path : path,
cookies: token
};
return WL.Server.invokeHttp(input);
}
Developer Works [DW] article correctly says the call sequence. It should be [assuming your mobile application is on customers mobile phone and he/she is operating on internet]
Worklight Mobile Client -> Data Power -> Worklight Server
The reason for this is, datapower acts as a ESB layer providing gateway for all the enterprise services. In a typical environment your Worklight server will be inside intranet and datapower will be on DMZ zone. Now Datapower needs to provide a gateway to worklight service [in your case what you call as adapter]. So the client code on mobile handset is even not aware about any worklight server. It calls the datapower proxy service which in turn scrutinize the request and if valid pass it to backend worklight server. When a response comes back it is also examined and forwarded to client application.
Exactly hosting this service on datapower is relatively easy but making it working requires a lot of effort. LTPA token plays a key role over here in validating client.
Hope this answers your question.
- Ajitabh

Login module in Titanium

Any one has experience in development of Login module with ProviderService.Src.
I need to develop a login module with the webservice using Titanium Appcelerator. It needs to take two strings (Username & Password) and return true/false. I need to send entered login and password via web service and receive true/false. The webservice is
http://46.18.8.42/FareBids.Service/FareBids.ServiceLayer.ProviderService.svc
Please some one guide me how to create a Login module with it? I got information which says me to use SUDS. Can some one help me on this with code(if possible)
Help would really be appreciated. Thanks.
Use a webservice http client. This should do it, you will have to tune this to your specific webservice and obviously collect data from the user, but how to do that is well documented in the most basic Titanium tutorials.
var loginSrv = Ti.Network.createHTTPClient({
onload : function(e) {
// If the service returns successfully : true, or false
var isUserAllowed = this.responseText;
},
onerror : function(e) {
// Web service failed for some reason
Ti.API.info(this.responseText);
Ti.API.info('webservice failed with message : ' + e.error);
}
});
loginSrv.open('POST', 'http://46.18.8.42/FareBids.Service/FareBids.ServiceLayer.ProviderService.svc');
// you may have to change the content type depending on your service
loginSrv.setRequestHeader("Content-Type", "application/json");
var sendObj = {loginid : 'someid', pwd : 'somepassword'};
loginSrv.send(obj);