Archive for the ‘Development’ Category

Domino Authentication using AJAX and JSON

Monday, November 25th, 2013

A while back, I had a requirement for a Domino hosted public jQuery Mobile web application to access private data held on the same Domino server in a database which required authentication, but from within the app itself, using either stored credentials or those provided via an in-app pop-up dialog.

Whist I found plenty of useful How-to’s on Domino Authentication via web pages and associated customisations, I just couldn’t seem to find what I was specifically looking for – although they did provide me with plenty of pointers and ideas to try…

Eventually, after much research and even more experimentation, I finally managed to pull all of the pieces of the puzzle together and produced a very simple solution which not only fulfilled all of my requirements, but is also as secure as it can to be (when using HTTPS).

Alas, this aspect of the web app has yet to make it into the app as originally planned, so in the meantime I thought that I’d document how to do this should anyone else out there be struggling to do the same…

It uses traditional Domino web design techniques, and I assume that the reader is comfitable with using javascript to make AJAX/JSON calls using jQuery, and is already familiar with Domino ACL settings for both Anonymous and Authenticated database access.

For the purposes of this article and to keep this simple for now, I shall assume that both the web application and the private data are stored in separate databases, called for example, PublicApp.nsf and PrivateData.nsf respectively, but on the same Domino server.

Stage 1 – Domino Pages.

First we need to create a couple of very basic Pages – each of which simply returns JSON data back to the caller using Computed Fields to fill in the missing blanks.

In the web app database (ie PublicApp.nsf), create a single page called getLoginStatus – which just returns some basic JSON data pertaining to the connected user, in particular whether they are authenticated or not.

This Page contains just the following:-

{

"authenticated": Computed Value,

"user":
{

"username":"Computed Value"

},

"returnStatus": "0",
"returnResponse": "Success"

}

Now set the authenticated Computed Value to:-

@If(@Name([CN];@UserName)= “Anonymous”;”false”; “true”)

and the username Computed Value (note the enclosing quotes) to:-

@Name([CN];@UserName)

Finally in its Page Properties, set Web Access = Other of type application/json, and ensure that this page is accessible by both Anonymous and Authenticated users.

After saving this page, copy it into the Private Database (ie PrivateData.nsf), renaming it as doLoginSuccessAuth in the process.

Ensure that this second page is only accessible to Authenticated users of the database. It is this second page that we actually use for login attempts.

Stage 2 – Javascipt.

Second, we need to add to the web app, some javascript functions plus a couple of global variables which act as URL pointers to the web app and private data.

The functions are:-

getLogonStatus – gets the getLogonStatus page data (returned as JSON) from PublicApp.nsf.

doLogout – sends the logout parameter (to PrivateData.nsf).

doLogin – attempts to get the doLogonSuccessAuth page data from PrivateData.nsf after POSTing to it the users login credentials.

getPrivateData – attempts to get the private page data from PrivateData.nsf.

This is the minimum code required – I’ve stripped out all of the original code – and whilst there is minimal comment, the code should be fairly self explanatory:-

// Global URL pointers for separate public and private databases

var homeURL = "http://MyServerName/PublicApp.nsf"
var dataURL = "http://MyServerName/PrivateData.nsf"

function getLogonStatus() {

function onSuccess(ajax_results, status, xhr) {

// get a value from returned JSON
var usernameLoggedOn = ajax_results.user.username;

if (ajax_results.authenticated) {

alert("getLogonStatus - Authenticated");

/*
* We are successfully accessing Domino
* as an Authenticated
* (non-anonymous) user.
* Code appropriate actions here...
*/

} else {

alert("getLogonStatus - Non-authenticated");

/*
* We are successfully accessing Domino
* as a Non-authenticated
* (Anonymous) user.
* Code appropriate actions here...
*/

}

};

function onError(xhr, status, errorThrown) {

alert("getLogonStatus - Error");

/*
* An error has occurred.
* Code appropriate actions here...
*/

};

$.ajax( {

url : homeURL + "/getLoginStatus?OpenPage",
dataType : 'json',
success : onSuccess,
error : onError

});

};

function doLogout() {

function onSuccess(ajax_results, status, xhr) {

alert("doLogout - Successful");

/*
* We have successfully logged out of Domino.
* Code appropriate actions here...
*/

};

function onError(xhr, status, errorThrown) {

alert("doLogout - Error");

/*
* An error has occurred.
* Code appropriate actions here...
*/

};

$.ajax( {

url : dataURL + "/?Logout&RedirectTo=" + homeURL
+ "/getLoginStatus?OpenPage",
dataType : 'json',
success : onSuccess,
error : onError

});

};

function doLogin(loginUsername, loginPassword) {

var loginRedirectTo = dataURL
+ "/dologinSuccessAuth?OpenPage";

var loginObject = {
username : loginUsername,
password : loginPassword,
redirectto : loginRedirectTo
};

function onSuccess(ajax_results, status, xhr) {

alert("doLogin - Successful");

/*
* We have successfully logged in to Domino
* using the provided
* credentials.
* Code appropriate actions here...
*/

};

function onError(xhr, status, errorThrown) {

if (status == "parsererror") {
// invalid JSON returned

alert("doLogin - Error Authentication");

/*
* An authentication error has occurred.
* Code appropriate actions here...
*/

} else {

alert("doLogin - Error");

/*
* An error has occurred.
* Code appropriate actions here...
*/

}

};

$.ajax( {

// If login successful returns the contents of
// doLoginSuccessAuth page
// (which requires authentication).
// else, Domino returns the HTML login page
// which we do not use

url : dataURL + "/?Login",
dataType : 'json',
type : 'POST',
data : loginObject,
success : onSuccess,
error : onError
});

};

function getPrivateData() {

function onSuccess(ajax_results, status, xhr) {

alert("getPrivateData - Successful");

/*
* We have successfully logged in to Domino
* using the provided
* credentials.
* Code appropriate actions here...
*/

};

function onError(xhr, status, errorThrown) {

if (status == "parsererror") {

alert("getPrivateData - Error Authentication");

/*
* An authentication error has occurred.
* Code appropriate actions here...
*/

} else {

alert("getPrivateData - Error");

/*
* An error has occurred.
* Code appropriate actions here...
*/

}

};

$.ajax( {

url : dataURL + "/getDataPrivateAuth?OpenPage",
dataType : 'json',
success : onSuccess,
error : onError

});

};

And that is all there is to it!

The above has been successfully tested against Domino 9 – I’ve not tried using Domino Data Services (DDS), although I see no reason why it would not work – and it should also be fine with all recent Domino versions, as it has no dependancies on XPages. That said, your own mileage may vary.

Enjoy!

iOS Device Remote Web Debugging in Three Easy Steps (but only if you’ve already got a Mac!)

Thursday, September 12th, 2013

I’ve recently been doing a lot of iOS (and Android) mobile web application development, and its often been useful to be able to inspect an application on an actual device, particularly when looking at performance issues.

As of iOS 6 Apple made this very easy to do with the Web Inspector function, which replaced the original Debug Console:-

1. Enable Web Inspector on the mobile device using Settings > Safari > Advanced

developersettings_2x

debugconsoleon_2x

2. Connect the iOS device to your Mac using a USB cable, and open the website that you want to inspect

3. On the Mac’s desktop Safari (assuming that you already have the Develop menu enabled in your Preferences), from the Develop drop-down menu simply select the connected iOS device type/name, and then from it’s sub-menu, the name of the website to inspect.

developmenu_2x

Most of the desktop Safari Web Inspector functions are now available to remotely inspect and debug the selected iOS website.

webinspector