Thread: [Cppcms-users] json_rpc and json questions
Brought to you by:
artyom-beilis
From: Daniel V. <chi...@gm...> - 2011-05-18 20:57:20
|
Hello, Question 1. I am implementing a json rpc server (cppcms::rpc::json_rpc_server) with privileges. One possible solution is for each rpc method do the following: void my_rpc_server::get_sensible_data() { if ( check_privileges() ) { // method implementation //... } else { return_error("not authorized"); } }; The problem is that I think this solution is not good because I would like to decouple the privilege system of the rpc methods definitions. Another theoretical solution would be extend virtual main method to add desired pre actions: class my_rcp : public cppcms::rpc::json_rpc_server { virtual void main(std::string); }; void main(std::string //unused) { json_rpc_request req = parse_json_rpc_request(context()); // Ideally this method should be protected and implemented in json_rpc_server. // Added pre actions if ( check_privileges(req.method_name) ) { dispatch_request(req); // Ideally this method should be protected and implemented in json_rpc_server. } else { return_error("not authorised"); } } AFAIK that is not posible with current json_rpc_server implementation. What is the best approach to add pre actions (ie: check privileges) to rpc method invocation?. Question 2. I can't implement a json rpc method with a json::value argument, for example the following example not compile: void my_rpc_server::my_method(cppcms::json::value v) { } One posible workaround is define a json::value to json::value trait: namespace cppcms { namespace json { template<> struct traits<value> { static value get(value const &v) { return v; } static void set(value &v,value const &in) { v = in; } }; }} // end cppcms::json But I guest it is not optimal because nedless copy overhead. Thank you. |
From: Artyom B. <art...@ya...> - 2011-05-19 07:07:21
|
>Question 1. > >I am implementing a json rpc server (cppcms::rpc::json_rpc_server) with >privileges. > >One possible solution is for each rpc method do the following: > >void my_rpc_server::get_sensible_data() >{ >if ( check_privileges() ) { > >// method implementation >//... >} >else { >return_error("not authorized"); >} >}; It depends on the level you check the privileges and how do you want to handle an answer and protocol. If you use HTTP session to check the privileges then you can do different things: 1. Return 403 Forbidden status on HTTP level before you even access to RPC service. You can overload the main function and check permissions, but this is generally limited for entire service not specific methods. This is something like "prevent executable from running as you don't have permissions to run it at OS leve" 2. Return a error code for specific call on the protocol level. This is something like "tell the chroot() or unlink() system calls return error code EACCES" It is really a question of your design and the design of the protocol. If some methods are forbidden, return error code is best, if all the service is forbidden return 403 as above. > >The problem is that I think this solution is not good because I would like to >decouple the privilege system of the rpc methods definitions. > >Another theoretical solution would be extend virtual main method to add desired >pre actions: > >class my_rcp : public cppcms::rpc::json_rpc_server >{ >virtual void main(std::string); >}; > > >void main(std::string //unused) >{ >json_rpc_request req = parse_json_rpc_request(context()); // Ideally this method > >should be protected and implemented in json_rpc_server. > This is why it is virtual. You want pre/post-actions? void main(std::string param) { // some pre-action cppcms::rpc::json_rpc_server::main(param); // some post-actions } >// Added pre actions > >if ( check_privileges(req.method_name) ) >{ >dispatch_request(req); // Ideally this method should be protected and >implemented in json_rpc_server. >} >else { >return_error("not authorised"); >} >} > > >AFAIK that is not posible with current json_rpc_server implementation. > AFAIK it should work fine, just overload main. > >Question 2. > >I can't implement a json rpc method with a json::value argument, for example the > >following example not compile: > >void my_rpc_server::my_method(cppcms::json::value v) >{ >} > >One posible workaround is define a json::value to json::value trait: > >namespace cppcms { namespace json { > template<> > struct traits<value> { > static value get(value const &v) { > return v; > } > static void set(value &v,value const &in) { > v = in; > } > }; >}} // end cppcms::json > >But I guest it is not optimal because nedless copy overhead. > If you want "native" json parameter you should create method that receives an array as parameter my_method(cppcms::json::array const &v) { } And the use something like boost::bind to create a reference. bind("sum",boost::bind(&json_service::my_method,this,_1),method_role); Or if you wan't want to use boost struct binder { binder(my_service &s) : s_(&s) void operator()(cppcms::json::array const &v) const { s_->my_method(v); } my_service *s_; }; And then bind("sum",binder(this),method_role); Actually you bring a good point, I need to provide such binder my default something like: cppcms::rpc::json_native_method in addition to json_method Fill a feature request for the last one so I will not forget. Best. Artyom |
From: Daniel V. <chi...@gm...> - 2011-05-19 17:08:40
|
On Thu, 2011-05-19 at 00:07 -0700, Artyom Beilis wrote: > > This is why it is virtual. You want pre/post-actions? > > void main(std::string param) > { > // some pre-action > cppcms::rpc::json_rpc_server::main(param); > // some post-actions > } > > The privilege validations depends on session() object (user and his rights) and method name. Then: void main(std::string param) { if( check_privileges(context()) ) { cppcms::rpc::json_rpc_server::main(param); } else { // not authorized } } So if I do just that, the request parsing is made twice. One for obtain method name for check_privileges and another into json_rpc_server::main() function. I guess there are no other solution in actual design. Is it true? One solution is give to the user of json_rpc_server class the possibility to add pre action after parsing json request but before dispatching. Thanks. |
From: Artyom B. <art...@ya...> - 2011-05-21 09:31:04
|
> So if I do just that, the request parsing is made twice. One for obtain > method name for check_privileges and another into json_rpc_server::main() > function. I guess there are no other solution in actual design. Is it true? If the privilege control is made on the level of each specific method like get(id) // for all update(id,new_value) // for privilege user Then you should check it inside method and not outside, void update(std::string const &id,my_object const &vale) { if(!check_permissions()) { return; } objects_[id]=value; } void get(std::string const &id) { return_result(objects_[id]); } bool check_permissions() { if(session().get("role","nobody")!="admin") { return_response("Not authorised"); return false; } return true; } The point you should not decouple parts of code that are truly connected. This way you know from looking to the method its permissions. Consider you add in future new method add() that is for priviliged users thus you have to add permissions control in one place and method itself in other. It is dangerous practice. Artyom |
From: Artyom B. <art...@ya...> - 2011-05-21 09:40:52
|
Small note, instead of: return_response("Not authorised"); return false; You can also return a error on HTTP level (not JSON-RPC): context().response().make_error_response(cppcms::http::response::forbidden); return false; But I think this is generally bad idea to make a error response on transport level rather then on JSON-RPC level. Artyom |