summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerrell Lipman <derrell@samba.org>2007-01-07 23:06:50 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:37:13 -0500
commit9639836022adcb62c72520f799a89d0f727f224d (patch)
tree26f7331426c94f96f502a8bf8641fb88ffad74d4
parenta04a3b8bc21101e6a11bad04c3d5c9655fa606b4 (diff)
downloadsamba-9639836022adcb62c72520f799a89d0f727f224d.tar.gz
samba-9639836022adcb62c72520f799a89d0f727f224d.tar.bz2
samba-9639836022adcb62c72520f799a89d0f727f224d.zip
r20600: Web Application Framework
- Add authentication. The Web Application Framework can now be called directly and it will rqeuire authentication if required, and should re-query the user to log in when the session expires. - General clean-up (This used to be commit 27c5d7dca6fa4e0811c1b8bb52d1db3d1824462c)
-rw-r--r--services/json_auth.esp58
-rw-r--r--services/request.esp87
-rw-r--r--services/resources.esp6
-rw-r--r--services/samba/system.esp84
-rw-r--r--webapps/scripting/common.js28
-rw-r--r--webapps/scripting/preauth.esp31
-rw-r--r--webapps/swat/source/class/swat/main/AbstractModuleFsm.js251
-rw-r--r--webapps/swat/source/class/swat/main/Authenticate.js152
-rw-r--r--webapps/swat/source/class/swat/main/Main.js10
-rw-r--r--webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js2
-rw-r--r--webapps/swat/source/class/swat/module/statistics/Fsm.js4
-rw-r--r--webapps/swat/source/class/swat/module/statistics/Gui.js2
12 files changed, 634 insertions, 81 deletions
diff --git a/services/json_auth.esp b/services/json_auth.esp
index 0fdd98037d..57fbd7aaac 100644
--- a/services/json_auth.esp
+++ b/services/json_auth.esp
@@ -1,13 +1,67 @@
<%
+libinclude("auth.js");
+
/* Return true to allow access; false otherwise */
-function json_authenticate(serviceComponents, method, scriptTransportId)
+function json_authenticate(serviceComponents, method, scriptTransportId, error)
{
- // Don't allow any access via ScriptTransport, for now.
+ // Don't allow any access via ScriptTransport, for now. There are serious
+ // potential security exploits that will need to be protected against when
+ // we do want to allow use of ScriptTransport. -- djl
if (scriptTransportId != jsonrpc.Constant.ScriptTransport.NotInUse)
{
+ error.setError(jsonrpc.Constant.ServerError.PermissionDenied,
+ "Permission denied");
+ return false;
+ }
+
+ // Does the requested method require authentication?
+ if (! _authentication_required(serviceComponents, method))
+ {
+ // Nope. Let 'em in.
+ return true;
+ }
+
+ // Did our session expire?
+ if (request['SESSION_EXPIRED'] == "True")
+ {
+ // Yup.
+ error.setError(jsonrpc.Constant.ServerError.SessionExpired,
+ "Session expired");
+ error.setInfo(getDomainList());
+ return false;
+ }
+
+ // Are we authenticated?
+ if (! session.AUTHENTICATED)
+ {
+ // Nope.
+ error.setError(jsonrpc.Constant.ServerError.NotLoggedIn,
+ "Not logged in");
+ error.setInfo(getDomainList());
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
+ * Return true if authentication is required for the specified method;
+ * false otherwise.
+ */
+function _authentication_required(serviceComponents, method)
+{
+ var m = join(".", serviceComponents) + "." + method;
+
+ // See if this method requires authentication
+ if (m == "samba.system.login" ||
+ m == "samba.system.logout")
+ {
+ // Nope.
return false;
}
+ // Anything not listed above requires authentication
return true;
}
diff --git a/services/request.esp b/services/request.esp
index 6f7e61e6e4..ae106be8ea 100644
--- a/services/request.esp
+++ b/services/request.esp
@@ -13,7 +13,6 @@
* This is a simple JSON-RPC server.
*/
-
/* Bring in the json format/parse functions */
jsonrpc_include("json.esp");
@@ -30,6 +29,10 @@ string_init(global);
/* Bring the system functions into the global frame */
sys_init(global);
+/* Bring the session functions into the global frame */
+system_session(global);
+
+
function printf()
{
print(vsprintf(arguments));
@@ -44,7 +47,7 @@ function printf()
jsonrpc = new Object();
jsonrpc.Constant = new Object();
jsonrpc.Constant.ErrorOrigin = new Object(); /* error origins */
-jsonrpc.Constant.ErrorCode = new Object(); /* server-generated error codes */
+jsonrpc.Constant.ServerError = new Object(); /* server-generated error codes */
jsonrpc.method = new Object(); /* methods available in requested class */
/*
@@ -74,7 +77,7 @@ jsonrpc.Constant.ErrorOrigin.Client = 4;
* The default error code, used only when no specific error code is passed to
* the JsonRpcError constructor. This code should generally not be used.
*/
-jsonrpc.Constant.ErrorCode.Unknown = 0;
+jsonrpc.Constant.ServerError.Unknown = 0;
/**
* Error code, value 1: Illegal Service
@@ -82,14 +85,14 @@ jsonrpc.Constant.ErrorCode.Unknown = 0;
* The service name contains illegal characters or is otherwise deemed
* unacceptable to the JSON-RPC server.
*/
-jsonrpc.Constant.ErrorCode.IllegalService = 1;
+jsonrpc.Constant.ServerError.IllegalService = 1;
/**
* Error code, value 2: Service Not Found
*
* The requested service does not exist at the JSON-RPC server.
*/
-jsonrpc.Constant.ErrorCode.ServiceNotFound = 2;
+jsonrpc.Constant.ServerError.ServiceNotFound = 2;
/**
* Error code, value 3: Class Not Found
@@ -99,14 +102,14 @@ jsonrpc.Constant.ErrorCode.ServiceNotFound = 2;
* detailed than "Method Not Found", but that error would always also be legal
* (and true) whenever this one is returned. (Not used in this implementation)
*/
-jsonrpc.Constant.ErrorCode.ClassNotFound = 3; // not used in this implementation
+jsonrpc.Constant.ServerError.ClassNotFound = 3;
/**
* Error code, value 4: Method Not Found
*
* The method specified in the request is not found in the requested service.
*/
-jsonrpc.Constant.ErrorCode.MethodNotFound = 4;
+jsonrpc.Constant.ServerError.MethodNotFound = 4;
/*
* Error code, value 5: Parameter Mismatch
@@ -118,7 +121,7 @@ jsonrpc.Constant.ErrorCode.MethodNotFound = 4;
* This error is also used to indicate an illegal parameter value, in server
* scripts.
*/
-jsonrpc.Constant.ErrorCode.ParameterMismatch = 5;
+jsonrpc.Constant.ServerError.ParameterMismatch = 5;
/**
* Error code, value 6: Permission Denied
@@ -129,23 +132,50 @@ jsonrpc.Constant.ErrorCode.ParameterMismatch = 5;
* authentication. If the caller has not properly authenticated to use the
* requested method, this error code is returned.
*/
-jsonrpc.Constant.ErrorCode.PermissionDenied = 6;
+jsonrpc.Constant.ServerError.PermissionDenied = 6;
+
+/*** Errors generated by this server which are not qooxdoo-standard ***/
/*
- * Error code, value 7: Unexpected Output
+ * Error code, value 1000: Unexpected Output
*
* The called method illegally generated output to the browser, which would
* have preceeded the JSON-RPC data.
*/
-jsonrpc.Constant.ErrorCode.UnexpectedOutput = 7;
+jsonrpc.Constant.ServerError.UnexpectedOutput = 1000;
/*
- * Error code, value 8: Resource Error
+ * Error code, value 1001: Resource Error
*
* Too many resources were requested, a system limitation on the total number
* of resources has been reached, or a resource or resource id was misused.
*/
-jsonrpc.Constant.ErrorCode.ResourceError = 8;
+jsonrpc.Constant.ServerError.ResourceError = 1001;
+
+/*
+ * Error code, value 1002: Not Logged In
+ *
+ * The user has logged out and must re-authenticate, or this is a brand new
+ * session and the user must log in.
+ *
+ */
+jsonrpc.Constant.ServerError.NotLoggedIn = 1002;
+
+/*
+ * Error code, value 1003: Session Expired
+ *
+ * The session has expired and the user must re-authenticate.
+ *
+ */
+jsonrpc.Constant.ServerError.SessionExpired = 1003;
+
+/*
+ * Error code, value 1004: Login Failed
+ *
+ * An attempt to log in failed.
+ *
+ */
+jsonrpc.Constant.ServerError.LoginFailed = 1004;
@@ -250,6 +280,14 @@ function _JsonRpcError_create(origin, code, message)
}
o.setScriptTransportId = _setScriptTransportId;
+ function _setInfo(info)
+ {
+ // Add the info field only if info is actually provided.
+ // This is an extension to qooxdoo's normal Error return value.
+ this.data.info = info;
+ }
+ o.setInfo = _setInfo;
+
function _Send()
{
var error = this;
@@ -276,7 +314,7 @@ var jsonInput = null;
/* Allocate a generic error object */
error = jsonrpc.createError(jsonrpc.Constant.ErrorOrigin.Server,
- jsonrpc.Constant.ErrorCode.Unknown,
+ jsonrpc.Constant.ServerError.Unknown,
"Unknown error");
/* Assume (default) we're not using ScriptTransport */
@@ -329,7 +367,7 @@ var nameFirstLetter =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
/*
- * Ensure the method name is kosher. A meethod name should be:
+ * Ensure the method name is kosher. A method name should be:
*
* - first character is in [a-zA-Z]
* - other characters are in [_a-zA-Z0-9]
@@ -339,7 +377,7 @@ var nameFirstLetter =
if (strspn(jsonInput.method, nameChars) != strlen(jsonInput.method))
{
/* There's some illegal character in the service name */
- error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound,
+ error.setError(jsonrpc.Constant.ServerError.MethodNotFound,
"Illegal character found in method name.");
error.Send();
return;
@@ -348,7 +386,7 @@ if (strspn(jsonInput.method, nameChars) != strlen(jsonInput.method))
/* Now ensure that it begins with a letter */
if (strspn(substr(jsonInput.method, 0, 1), nameFirstLetter) != 1)
{
- error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound,
+ error.setError(jsonrpc.Constant.ServerError.MethodNotFound,
"The method name does not begin with a letter");
error.Send();
return;
@@ -366,7 +404,7 @@ if (strspn(substr(jsonInput.method, 0, 1), nameFirstLetter) != 1)
if (strspn(jsonInput.service, "." + nameChars) != strlen(jsonInput.service))
{
/* There's some illegal character in the service name */
- error.setError(jsonrpc.Constant.ErrorCode.IllegalService,
+ error.setError(jsonrpc.Constant.ServerError.IllegalService,
"Illegal character found in service name.");
error.Send();
return;
@@ -381,7 +419,7 @@ if (strspn(jsonInput.service, "." + nameChars) != strlen(jsonInput.service))
*/
if (typeof(strstr(jsonInput.service, "..")) != "pointer")
{
- error.setError(jsonrpc.Constant.ErrorCode.IllegalService,
+ error.setError(jsonrpc.Constant.ServerError.IllegalService,
"Illegal use of two consecutive dots in service name");
error.Send();
return;
@@ -395,7 +433,7 @@ for (var i = 0; i < serviceComponents.length; i++)
{
if (strspn(substr(serviceComponents[i], 0, 1), nameFirstLetter) != 1)
{
- error.setError(jsonrpc.Constant.ErrorCode.IllegalService,
+ error.setError(jsonrpc.Constant.ServerError.IllegalService,
"A service name component does not begin with a letter");
error.Send();
return;
@@ -413,7 +451,7 @@ var servicePath = join("/", serviceComponents) + ".esp";
if (jsonrpc_include(servicePath))
{
/* Couldn't find the requested service */
- error.setError(jsonrpc.Constant.ErrorCode.ServiceNotFound,
+ error.setError(jsonrpc.Constant.ServerError.ServiceNotFound,
"Service class `" + servicePath + "` does not exist.");
error.Send();
return;
@@ -451,7 +489,7 @@ if (valid)
if (! valid)
{
- error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound,
+ error.setError(jsonrpc.Constant.ServerError.MethodNotFound,
"Method `" + jsonInput.method + "` not found.");
error.Send();
return;
@@ -467,10 +505,9 @@ if (! valid)
*/
if (! json_authenticate(serviceComponents,
jsonInput.method,
- scriptTransportId))
+ scriptTransportId,
+ error))
{
- error.setError(jsonrpc.Constant.ErrorCode.PermissionDenied,
- "Permission denied");
error.Send();
return;
}
diff --git a/services/resources.esp b/services/resources.esp
index d491ed5701..e7fd164c34 100644
--- a/services/resources.esp
+++ b/services/resources.esp
@@ -39,7 +39,7 @@ function _resourcesCreate()
{
/* Yup. */
error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
- error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ error.setError(jsonrpc.Constant.ServerError.ResourceError,
"Session limit on resources (" +
RESOURCE_LIMIT +
") exceeded.");
@@ -79,7 +79,7 @@ function _resourcesCreate()
{
/* Nope. */
error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
- error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ error.setError(jsonrpc.Constant.ServerError.ResourceError,
"Resource not found.");
return error;
}
@@ -130,7 +130,7 @@ function _resourcesCreate()
{
/* Nope. */
error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
- error.setError(jsonrpc.Constant.ErrorCode.ResourceError,
+ error.setError(jsonrpc.Constant.ServerError.ResourceError,
"Resource not found.");
return error;
}
diff --git a/services/samba/system.esp b/services/samba/system.esp
index e75151e93b..59844cda39 100644
--- a/services/samba/system.esp
+++ b/services/samba/system.esp
@@ -17,6 +17,90 @@ jsonrpc_include("resources.esp");
/**
+ * Authenticate and log in
+ *
+ * @param params[0]
+ * User name
+ *
+ * @param params[1]
+ * Password
+ *
+ * @param params[2]
+ * Domain
+ *
+ * @param error
+ * An object of class JsonRpcError.
+ *
+ * @return
+ * Success: "Logged in"
+ * Failure: error event, origin=Server, code=LoginFailed
+ */
+function _login(params, error)
+{
+ var ret;
+ var creds = credentials_init();
+
+ creds.set_username(params[0]);
+ creds.set_password(params[1]);
+ creds.set_domain(params[2]);
+ creds.set_workstation(request['REMOTE_HOST']);
+ auth = userAuth(creds, request['REMOTE_SOCKET_ADDRESS']);
+
+ if (auth == undefined)
+ {
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ServerError.LoginFailed,
+ "Invalid login.");
+ ret = error;
+ }
+ else if (auth.result)
+ {
+ session.AUTHENTICATED = true;
+ session.authinfo = new Object();
+
+ session.authinfo.username = auth.username;
+ session.authinfo.domain = auth.domain;
+ session.authinfo.credentials = creds;
+ session.authinfo.session_info = auth.session_info;
+
+ ret = "Logged in";
+ }
+ else if (auth.report == undefined)
+ {
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ServerError.LoginFailed,
+ "Login failed.");
+ ret = error;
+ }
+ else
+ {
+ error.setOrigin(jsonrpc.Constant.ErrorOrigin.Server);
+ error.setError(jsonrpc.Constant.ServerError.LoginFailed,
+ "Login failed: " + auth.report);
+ ret = error;
+ }
+
+ return ret;
+}
+jsonrpc.method.login = _login;
+
+
+
+/**
+ * Retrieve the list of open resources (for debugging)
+ *
+ * @return "Logged out"
+ */
+function _logout(params, error)
+{
+ session.AUTHENTICATED = false;
+ return "Logged out";
+}
+jsonrpc.method.logout = _logout;
+
+
+
+/**
* Retrieve the list of open resources (for debugging)
*/
function _get_open_resources(params, error)
diff --git a/webapps/scripting/common.js b/webapps/scripting/common.js
index fe25287a74..c111089bd8 100644
--- a/webapps/scripting/common.js
+++ b/webapps/scripting/common.js
@@ -69,34 +69,6 @@ function page_footer() {
/*
- check if a uri is one of the 'always allowed' pages, even when not logged in
- This allows the login page to use the same style sheets and images
-*/
-function always_allowed(uri) {
- var str = string_init();
-
- /* allow jsonrpc-based applications to do their own authentication */
- var s = str.split('/', uri);
- if (s[0] == "" && s[1] == 'apps') {
- return true;
- }
-
- var s = str.split('.', uri);
- if (s.length < 2) {
- return false;
- }
-
- var ext = s[s.length-1];
- var allowed = new Array("ico", "gif", "png","css", "js");
- for (i in allowed) {
- if (allowed[i] == ext) {
- return true;
- }
- }
- return false;
-}
-
-/*
display a table element
*/
function table_element(i, o) {
diff --git a/webapps/scripting/preauth.esp b/webapps/scripting/preauth.esp
index 489f6b5004..e6d04faf8d 100644
--- a/webapps/scripting/preauth.esp
+++ b/webapps/scripting/preauth.esp
@@ -5,6 +5,36 @@ include("/scripting/common.js");
output at all then that output is returned and the requested page
is not given or processed.
*/
+
+/*
+ check if a uri is one of the 'always allowed' pages, even when not logged in
+ This allows the login page to use the same style sheets and images
+*/
+function always_allowed(uri) {
+ var str = string_init();
+
+ /* allow jsonrpc-based applications to do their own authentication */
+ var s = str.split('/', uri);
+ if (s[0] == "" && s[1] == 'index.html') {
+ return true;
+ }
+
+ var s = str.split('.', uri);
+ if (s.length < 2) {
+ return false;
+ }
+
+ var ext = s[s.length-1];
+ var allowed = new Array("ico", "gif", "png","css", "js");
+ for (i in allowed) {
+ if (allowed[i] == ext) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
if (server['SERVER_PROTOCOL'] == "http" &&
server['TLS_SUPPORT'] == "True") {
write("redirect to https");
@@ -14,4 +44,5 @@ if (server['SERVER_PROTOCOL'] == "http" &&
/* present the login page */
include("/login.esp");
}
+
%>
diff --git a/webapps/swat/source/class/swat/main/AbstractModuleFsm.js b/webapps/swat/source/class/swat/main/AbstractModuleFsm.js
index 49222d90d4..fed11eb0d3 100644
--- a/webapps/swat/source/class/swat/main/AbstractModuleFsm.js
+++ b/webapps/swat/source/class/swat/main/AbstractModuleFsm.js
@@ -109,12 +109,25 @@ qx.Proto.addAwaitRpcResultState = function(module)
},
"onentry" :
- function(fsm, state)
+ function(fsm, event)
{
- // If we're coming from some other state...
- if (fsm.getPreviousState() != "State_AwaitRpcResult")
+ var bAuthCompleted = false;
+
+ // See if we just completed an authentication
+ if (fsm.getPreviousState() == "State_Authenticate" &&
+ event.getType() == "complete")
+ {
+ bAuthCompleted = true;
+ }
+_this.debug("bAuthCompleted=" + bAuthCompleted);
+
+ // If we didn't just complete an authentication and we're coming
+ // from some other state...
+ if (! bAuthCompleted &&
+ fsm.getPreviousState() != "State_AwaitRpcResult")
{
// ... then push the previous state onto the state stack
+_this.warn("PUSHING STATE");
fsm.pushState(false);
}
},
@@ -144,27 +157,63 @@ qx.Proto.addAwaitRpcResultState = function(module)
* Cause: "failed" (on RPC) where reason is PermissionDenied
*/
var trans = new qx.util.fsm.Transition(
- "Transition_AwaitRpcResult_to_GetAuthInfo",
+ "Transition_AwaitRpcResult_to_Authenticate",
{
"nextState" :
- qx.util.fsm.FiniteStateMachine.StateChange.POP_STATE_STACK,
+ "State_Authenticate",
"predicate" :
function(fsm, event)
{
var error = event.getData(); // retrieve the JSON-RPC error
- // Did we get get origin=Server, code=PermissionDenied ?
+ // Did we get get origin=Server, and either
+ // code=NotLoggedIn or code=SessionExpired ?
var origins = swat.main.AbstractModuleFsm.JsonRpc_Origin;
var serverErrors = swat.main.AbstractModuleFsm.JsonRpc_ServerError;
if (error.origin == origins.Server &&
- error.code == serverErrors.PermissionDenied)
+ (error.code == serverErrors.NotLoggedIn ||
+ error.code == serverErrors.SessionExpired))
{
return true;
}
// fall through to next transition, also for "failed"
return false;
+ },
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ var caption;
+
+ var error = event.getData(); // retrieve the JSON-RPC error
+ var serverErrors = swat.main.AbstractModuleFsm.JsonRpc_ServerError;
+
+ switch(error.code)
+ {
+ case serverErrors.NotLoggedIn:
+ caption = "Please log in.";
+ break;
+
+ case serverErrors.SessionExpired:
+ default:
+ caption = "Session Expired. Please log in.";
+ break;
+ }
+
+ // Retrieve the modal authentication window.
+
+ var loginWin = swat.main.Authenticate.getInstance(module);
+
+ // Set the caption
+ loginWin.setCaption(caption);
+
+ // Set the domain info
+ loginWin.setInfo(error.info);
+
+ // Open the authentication window
+ loginWin.open();
}
});
state.addTransition(trans);
@@ -247,6 +296,153 @@ qx.Proto.addAwaitRpcResultState = function(module)
}
});
state.addTransition(trans);
+
+ /*
+ * State: Authenticate
+ *
+ * Transition on:
+ * "execute" on login_button
+ */
+ var state = new qx.util.fsm.State(
+ "State_Authenticate",
+ {
+ "onentry" :
+ function(fsm, event)
+ {
+ // Retrieve the login window object
+ var win = module.fsm.getObject("login_window");
+
+ // Clear the password field
+ win.password.setValue("");
+
+ // If there's no value selected for domain...
+ if (win.domain.getValue() == null)
+ {
+ // ... then select the first value
+ win.domain.setSelected(win.domain.getList().getFirstChild());
+ }
+
+ // Retrieve the current RPC request
+ var rpcRequest = _this.getCurrentRpcRequest();
+
+ // Did we just return from an RPC request and was it a login request?
+ if (fsm.getPreviousState() == "State_AwaitRpcResult" &&
+ rpcRequest.service == "samba.system" &&
+ rpcRequest.params.length > 1 &&
+ rpcRequest.params[1] == "login")
+ {
+ // Yup. Display the result. Pop the old request off the stack
+ var loginRequest = _this.popRpcRequest();
+
+ // Retrieve the result
+ var result = loginRequest.getUserData("result");
+
+ // Did we succeed?
+ if (result.type == "failed")
+ {
+ // Nope. Just reset the caption, and remain in this state.
+ win.setCaption("Login Failed. Try again.");
+ }
+ else
+ {
+ // Login was successful. Generate an event that will transition
+ // us back to the AwaitRpcResult state to again await the result
+ // of the original RPC request.
+ win.dispatchEvent(new qx.event.type.Event("complete"), true);
+
+ // Reissue the original request. (We already popped the login
+ // request off the stack, so the current request is the original
+ // one.)
+ var origRequest = _this.getCurrentRpcRequest();
+
+ // Retrieve the RPC object */
+ var rpc = fsm.getObject("swat.main.rpc");
+
+ // Set the service name
+ rpc.setServiceName(origRequest.service);
+
+ // Reissue the request
+ origRequest.request =
+ qx.io.remote.Rpc.prototype.callAsyncListeners.apply(
+ rpc,
+ origRequest.params);
+
+ // Clear the password field, for good measure
+ win.password.setValue("");
+
+ // Close the login window
+ win.close();
+ }
+
+ // Dispose of the login request
+ loginRequest.request.dispose();
+ loginRequest.request = null;
+ }
+ },
+
+ "events" :
+ {
+ "execute" :
+ {
+ "login_button" :
+ "Transition_Authenticate_to_AwaitRpcResult_via_button_login"
+ },
+
+ "complete" :
+ {
+ "login_window" :
+ "Transition_Authenticate_to_AwaitRpcResult_via_complete"
+ }
+ }
+ });
+ fsm.addState(state);
+
+ /*
+ * Transition: Authenticate to AwaitRpcResult
+ *
+ * Cause: "execute" on login_button
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Authenticate_to_AwaitRpcResult_via_button_login",
+ {
+ "nextState" :
+ "State_AwaitRpcResult",
+
+ "ontransition" :
+ function(fsm, event)
+ {
+ // Retrieve the login window object
+ var win = fsm.getObject("login_window");
+
+ // Issue a Login call
+ _this.callRpc(fsm,
+ "samba.system",
+ "login",
+ [
+ win.userName.getValue(),
+ win.password.getValue(),
+ win.domain.getValue()
+ ]);
+ }
+ });
+ state.addTransition(trans);
+
+ /*
+ * Transition: Authenticate to AwaitRpcResult
+ *
+ * Cause: "complete" on login_window
+ *
+ * We've already re-issued the original request, so we have nothing to do
+ * here but transition back to the AwaitRpcResult state to again await the
+ * result of the original request.
+ */
+ var trans = new qx.util.fsm.Transition(
+ "Transition_Authenticate_to_AwaitRpcResult_via_complete",
+ {
+ "nextState" :
+ "State_AwaitRpcResult"
+ });
+ state.addTransition(trans);
};
@@ -292,7 +488,7 @@ qx.Proto.callRpc = function(fsm, service, method, params)
// Set the service name
rpc.setServiceName(rpcRequest.service);
- // Issue the request, skipping the already-specified service name
+ // Issue the request
rpcRequest.request =
qx.io.remote.Rpc.prototype.callAsyncListeners.apply(rpc,
rpcRequest.params);
@@ -435,21 +631,46 @@ qx.Class.JsonRpc_ServerError =
*/
PermissionDenied : 6,
+ /*** Errors generated by this server which are not qooxdoo-standard ***/
+
/*
- * Error code, value 7: Unexpected Output
+ * Error code, value 1000: Unexpected Output
*
* The called method illegally generated output to the browser, which would
* have preceeded the JSON-RPC data.
*/
- UnexpectedOutput : 7,
+ UnexpectedOutput : 1000,
/*
- * Error code, value 8: Resource Error
+ * Error code, value 1001: Resource Error
*
- * Too many resources were requested, a system limitation on the total
- * number of resources has been reached, or a resource or resource id was
- * misused.
+ * Too many resources were requested, a system limitation on the total number
+ * of resources has been reached, or a resource or resource id was misused.
*/
- ResourceError : 8
+ ResourceError : 1001,
+ /*
+ * Error code, value 1002: Not Logged In
+ *
+ * The user has logged out and must re-authenticate, or this is a brand new
+ * session and the user must log in.
+ *
+ */
+ NotLoggedIn : 1002,
+
+ /*
+ * Error code, value 1003: Session Expired
+ *
+ * The session has expired and the user must re-authenticate.
+ *
+ */
+ SessionExpired : 1003,
+
+ /*
+ * Error code, value 1004: Login Failed
+ *
+ * An attempt to log in failed.
+ *
+ */
+ LoginFailed : 1004
};
diff --git a/webapps/swat/source/class/swat/main/Authenticate.js b/webapps/swat/source/class/swat/main/Authenticate.js
new file mode 100644
index 0000000000..449a17d9ad
--- /dev/null
+++ b/webapps/swat/source/class/swat/main/Authenticate.js
@@ -0,0 +1,152 @@
+/*
+ * Copyright:
+ * (C) 2007 by Derrell Lipman
+ * All rights reserved
+ *
+ * License:
+ * LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
+ */
+
+/**
+ * Swat authentication window class
+ */
+qx.OO.defineClass("swat.main.Authenticate", qx.ui.window.Window,
+function(module)
+{
+ var o;
+ var fsm = module.fsm;
+
+ qx.ui.window.Window.call(this);
+
+ var addCaptionedWidget = function(caption, dest, addWidget)
+ {
+ // Add a row to the destination grid
+ dest.addRow();
+ var row = dest.getRowCount() - 1;
+ dest.setRowHeight(row, 24);
+
+ // Add the caption
+ var o = new qx.ui.basic.Label(caption);
+ dest.add(o, 0, row);
+
+ // Add the widget
+ o = addWidget();
+ o.setHeight(24);
+ dest.add(o, 1, row);
+
+ // Give 'em the varying data label
+ return o;
+ };
+
+
+ // Set characteristics of this window
+ this.set({
+ width : 380,
+ height : 200,
+ modal : true,
+ centered : true,
+ showClose : false,
+ showMaximize : false,
+ showMinimize : false,
+ showStatusbar : false,
+ allowClose : false,
+ allowMaximize : false,
+ allowMinimize : false,
+ resizeable : false,
+ moveable : false,
+ zIndex : 10000
+ });
+
+
+ // Create a grid layout
+ var grid = new qx.ui.layout.GridLayout();
+ grid.setLocation(14, 14);
+ grid.setDimension("90%", "90%");
+ grid.setVerticalSpacing(14);
+ grid.setPadding(14, 14);
+ grid.setRowCount(0);
+ grid.setColumnCount(2);
+ grid.setColumnWidth(0, 100);
+ grid.setColumnWidth(1, 200);
+
+
+ // Add an input box for the user name
+ this.userName = addCaptionedWidget("User Name", grid,
+ function()
+ {
+ return new qx.ui.form.TextField();
+ });
+
+ // Add an input box for the password
+ this.password = addCaptionedWidget("Password", grid,
+ function()
+ {
+ return new qx.ui.form.PasswordField();
+ });
+
+ // Add an input box for the password
+ this.domain = addCaptionedWidget("Domain", grid,
+ function()
+ {
+ // Create a combo box for for the domain
+ var combo = new qx.ui.form.ComboBox();
+ combo.setEditable(false);
+ return combo;
+ });
+
+ // Add a login button
+ this.login = addCaptionedWidget("", grid,
+ function()
+ {
+ return new qx.ui.form.Button("Login");
+ });
+
+ // Save this login button since we receive events on it
+ fsm.addObject("login_button", this.login);
+
+ // We want to receive "execute" events on this button
+ this.login.addEventListener("execute", fsm.eventListener, fsm);
+
+ // Add the grid to the window
+ this.add(grid);
+
+ // Add this window to the document
+ this.addToDocument();
+
+ // Save this window object
+ fsm.addObject("login_window", this);
+
+ // We want to receive "complete" events on this button (which we generate)
+ this.addEventListener("complete", fsm.eventListener, fsm);
+});
+
+
+
+qx.Proto.setInfo = function(info)
+{
+ this.debug(info);
+
+ // Remove everythingn from the domain list
+ this.domain.removeAll();
+
+ // Add the available domains
+ for (var i = 0; i < info.length; i++)
+ {
+ var item = new qx.ui.form.ListItem(info[i]);
+ this.domain.add(item);
+ }
+};
+
+
+/**
+ * Singleton Instance Getter
+ */
+qx.Class.getInstance = function(module)
+{
+ if (! this._instance)
+ {
+ this._instance = new this(module);
+ }
+
+ return this._instance;
+};
diff --git a/webapps/swat/source/class/swat/main/Main.js b/webapps/swat/source/class/swat/main/Main.js
index 7cc6b01736..fda6ba1115 100644
--- a/webapps/swat/source/class/swat/main/Main.js
+++ b/webapps/swat/source/class/swat/main/Main.js
@@ -10,6 +10,7 @@
/*
#require(swat.main.Module)
#require(swat.main.AbstractModule)
+#require(swat.main.Authenticate);
*/
/**
@@ -22,21 +23,22 @@ function()
});
/*
- * Register our supported modules
+ * Register our supported modules. The order listed here is the order they
+ * will appear in the Modules menu.
*/
//#require(swat.module.statistics.Statistics)
new swat.main.Module("Status and Statistics",
- swat.module.statistics.Statistics);
+ swat.module.statistics.Statistics);
//#require(swat.module.ldbbrowse.LdbBrowse)
new swat.main.Module("LDB Browser",
- swat.module.ldbbrowse.LdbBrowse);
+ swat.module.ldbbrowse.LdbBrowse);
//#require(swat.module.documentation.Documentation)
//#require(api.Viewer)
new swat.main.Module("API Documentation",
- swat.module.documentation.Documentation);
+ swat.module.documentation.Documentation);
/*
diff --git a/webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js b/webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
index 0abb3454c8..4ddc018595 100644
--- a/webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
+++ b/webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
@@ -37,7 +37,7 @@ qx.Proto.buildFsm = function(module)
"State_Idle",
{
"onentry" :
- function(fsm, state)
+ function(fsm, event)
{
// Did we just return from an RPC request?
if (fsm.getPreviousState() == "State_AwaitRpcResult")
diff --git a/webapps/swat/source/class/swat/module/statistics/Fsm.js b/webapps/swat/source/class/swat/module/statistics/Fsm.js
index 3083fed42a..b60501512a 100644
--- a/webapps/swat/source/class/swat/module/statistics/Fsm.js
+++ b/webapps/swat/source/class/swat/module/statistics/Fsm.js
@@ -61,7 +61,7 @@ qx.Proto.buildFsm = function(module)
"State_Idle",
{
"onentry" :
- function(fsm, state)
+ function(fsm, event)
{
// Did we just return from an RPC request?
if (fsm.getPreviousState() == "State_AwaitRpcResult")
@@ -83,7 +83,7 @@ qx.Proto.buildFsm = function(module)
},
"onexit" :
- function(fsm, state)
+ function(fsm, event)
{
// If we're not coming right back into this state...
if (fsm.getNextState() != "State_Idle")
diff --git a/webapps/swat/source/class/swat/module/statistics/Gui.js b/webapps/swat/source/class/swat/module/statistics/Gui.js
index 5968785e07..b5e11d4533 100644
--- a/webapps/swat/source/class/swat/module/statistics/Gui.js
+++ b/webapps/swat/source/class/swat/module/statistics/Gui.js
@@ -82,7 +82,7 @@ qx.Proto.buildGui = function(module)
dest.setRowHeight(row, 16);
// Add the caption
- o = new qx.ui.basic.Label(caption);
+ var o = new qx.ui.basic.Label(caption);
dest.add(o, 0, row);
// Add the text field that will contain varying data