Thanks for the suggestions, guys.
My final solution is to do the following
PHP Code:
var loginDialog;
Ext.lib.Ajax['runLoginDialog'] = function (object, callback, msg) {
if (loginDialog === undefined) {
loginDialog = new Ext.BasicDialog('login-dialog', {
width: 320, height: 180, modal: true, shadow: true, myform: new Ext.form.Form({ labelWidth: 100 }),
password_field: new Ext.form.TextField({ fieldLabel: 'Password', name: 'password', width:100, inputType: 'password' }),
user_field: new Ext.form.TextField({ fieldLabel: 'User Name', name: 'username', width:100 })
});
loginDialog.myform.add( loginDialog.user_field, loginDialog.password_field );
var submitFunction = function(dialog) {
var btn = (dialog.mybutton !== undefined ? dialog.mybutton : dialog);
Ext.Ajax.request({
params: { j_username : loginDialog.user_field.getValue(), j_password : loginDialog.password_field.getValue() },
url: 'j_acegi_security_check', originalCallback: btn.mycallback, originalObject: btn.myobject
});
loginDialog.myform.reset();
loginDialog.hide();
};
loginDialog.addKeyListener([10, 13], submitFunction);
loginDialog.mybutton = loginDialog.myform.addButton({ text: 'Continue', cls: 'x-btn-text-icon login', handler: submitFunction });
loginDialog.myform.render('j_acegi_security_check-form-ct');
}
document.getElementById('j_acegi_security_check-form-messages').innerHTML = (msg !== undefined ? msg : '');
loginDialog.mybutton.mycallback = callback;
loginDialog.mybutton.myobject = object;
loginDialog.show();
loginDialog.myform.reset();
loginDialog.user_field.focus();
}
Ext.lib.Ajax['handleTransactionResponse'] = function(o, callback, isAbort) {
if (!callback) {
this.releaseObject(o);
return;
}
/* if the request came from here originally, use it's callback */
var originalCallback = undefined, originalObject = undefined;
try {
originalCallback = callback.argument.options.originalCallback;
originalObject = callback.argument.options.originalObject;
if (originalCallback !== undefined) {
callback = originalCallback;
}
}
catch (e) {
}
var httpStatus, responseObject;
try {
httpStatus = (o.conn.status !== undefined && o.conn.status != 0) ? o.conn.status : 13030;
}
catch(e) {
httpStatus = 13030;
}
if (httpStatus >= 200 && httpStatus < 300) {
var response = o.conn.responseText;
if (response.indexOf('<meta name="Purpose" content="login" />') > 0) {
var index = response.indexOf('<div class="error">');
var errorDiv = undefined;
if (index > 0) {
var endIndex = response.substr(index + 19).indexOf('</div>') - 1;
errorDiv = response.substr(index + 19, endIndex);
}
Ext.lib.Ajax.runLoginDialog(o, callback, errorDiv);
}
else {
if (originalObject !== undefined) {
o.tId = originalObject.tId;
}
responseObject = this.createResponseObject(o, callback.argument);
if (callback.success) {
if (!callback.scope) {
callback.success(responseObject);
}
else {
callback.success.apply(callback.scope, [responseObject]);
}
}
}
}
else {
switch (httpStatus) {
case 12002:
case 12029:
case 12030:
case 12031:
case 12152:
case 13030:
responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
if (callback.failure) {
if (!callback.scope) {
callback.failure(responseObject);
}
else {
callback.failure.apply(callback.scope, [responseObject]);
}
}
break;
default:
if (originalObject !== undefined) {
o.tId = originalObject.tId;
}
responseObject = this.createResponseObject(o, callback.argument);
if (callback.failure) {
if (!callback.scope) {
callback.failure(responseObject);
}
else {
callback.failure.apply(callback.scope, [responseObject]);
}
}
}
}
this.releaseObject(o);
responseObject = null;
};
The critical parts are as follows (in order of definition above):- in the login dialog, the handler on the submit button puts the originating callback & request object in the button's configuration (in the line with url: 'j_acegi_security_check'), for use in the next step
- at the beginning of the handleTransactionResponse method, we recall the original callback & request object so that the results from the 'j_acegi_security_check' call can be applied to the original XMLHttpRequest, in the course of the normal handling of this method
- the handleTransactionResponse method detects the authentication failure and launches the login dialog based on the 'Purpose' meta tag.
This technique relies upon the feature of Acegi whereby it remembers your intended HTTP request in the Session, and returns the response to that request when you successfully authenticate.
Also, I've found the dozen or so locations in my code base where I make requests that might fail authentication, and I wrap those with a 'ping' request. That 'ping' request is usually the one that fails, and when it returns correctly, the wrapped request is then sent:
PHP Code:
function openFileWindow(url, name) {
Ext.Ajax.request({
url: 'images/ping.gif',
callback: function(options, success, response) {
openWindow(url, name, 850, 850);
}
});
}
Hope this mechanism helps someone else.
Regards,
Ben