From 9639836022adcb62c72520f799a89d0f727f224d Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 7 Jan 2007 23:06:50 +0000 Subject: 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 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 30 deletions(-) (limited to 'services') 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 @@ -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) */ -- cgit