From 9639836022adcb62c72520f799a89d0f727f224d Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 7 Jan 2007 23:06:50 +0000 Subject: [PATCH] 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) --- services/json_auth.esp | 58 +++- services/request.esp | 87 ++++-- services/resources.esp | 6 +- services/samba/system.esp | 84 ++++++ webapps/scripting/common.js | 28 -- webapps/scripting/preauth.esp | 31 +++ .../class/swat/main/AbstractModuleFsm.js | 251 ++++++++++++++++-- .../source/class/swat/main/Authenticate.js | 152 +++++++++++ webapps/swat/source/class/swat/main/Main.js | 10 +- .../source/class/swat/module/ldbbrowse/Fsm.js | 2 +- .../class/swat/module/statistics/Fsm.js | 4 +- .../class/swat/module/statistics/Gui.js | 2 +- 12 files changed, 634 insertions(+), 81 deletions(-) create mode 100644 webapps/swat/source/class/swat/main/Authenticate.js diff --git a/services/json_auth.esp b/services/json_auth.esp index 0fdd98037d6..57fbd7aaacd 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 6f7e61e6e4e..ae106be8ea9 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 d491ed5701c..e7fd164c34a 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 e75151e93b5..59844cda398 100644 --- a/services/samba/system.esp +++ b/services/samba/system.esp @@ -16,6 +16,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) */ diff --git a/webapps/scripting/common.js b/webapps/scripting/common.js index fe25287a74c..c111089bd87 100644 --- a/webapps/scripting/common.js +++ b/webapps/scripting/common.js @@ -68,34 +68,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 */ diff --git a/webapps/scripting/preauth.esp b/webapps/scripting/preauth.esp index 489f6b5004b..e6d04faf8d9 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 49222d90d43..fed11eb0d37 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 00000000000..449a17d9ad2 --- /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 7cc6b017363..fda6ba11155 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 0abb3454c8b..4ddc0185954 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 3083fed42af..b60501512a8 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 5968785e079..b5e11d45332 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 -- 2.34.1