taskrambler  0.1.9
Web server and task management solution.
route.c File Reference
#include <string.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <ctype.h>
#include "router.h"
#include "hash.h"
#include "session.h"
#include "http/request.h"
#include "http/response.h"
#include "application/application.h"
#include "utils/memory.h"
#include "commons.h"
+ Include dependency graph for route.c:

Go to the source code of this file.

Macros

#define COMMAND_LEN   128
 

Functions

HttpResponse routerRoute (Router this, HttpRequest request, Session sess)
 

Detailed Description

This is the generic application router.... Here RBAC can take place as every resource is always requested via an HTTP request.

Author
Georg Hopp

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file route.c.

Macro Definition Documentation

#define COMMAND_LEN   128

Definition at line 49 of file route.c.

Referenced by routerRoute().

Function Documentation

HttpResponse routerRoute ( Router  this,
HttpRequest  request,
Session  sess 
)
Todo:
now get all arguments if we have some
Todo:
somewhere here or above access control have to take place Default policy should be deny, anyway, there are a few resource that should be accessible even when not logged in...the are at least most of the assets as well as functions like version or sessinfo and in fact currentuse to have a way to find out that one is not logged in. In general a deny will be handled by storing an error message in some stash and then trigger a redirect to the login page. To be really rbac it seems neccessary to me to create a user "not logged in" and assign him the exceptions to the default deny policy. For the moment I assume that if there is no resource for the URL in the application it must be an asset and just return NULL indication that we still have no response for the request. Another thought... resources will be created dynamically by creating tasks or users or anything. Each of these resources may have options to admin them. This means most of the time to be able to modify them but additionally the creater of the resource might need the right to modify the rbac rules that apply to that resource. So, if I keep the real resources and their rbac configuration separated as planned it might be neccessary to give the creater of a resource the ability to modify both.

So lets assume user georg creates a task that might be identified by /task/uuid(task). Then additionally an rbac resource will be created identified by /rbac_resource/uuid(/task/uuid(task)). User georg will have all rights on both resources. This means that rbac resources are resources by their own but how to control the access to these, I can't build another rbac resource and another and and and... so I think it is neccessary that every resource as it is has to hold their access in itself. The creating user will gain access to all REST operations as well as the right to change access control (which again are REST operations on these.

Sidenote: I use a slightly differen naming than the ansi spec uses I the term resource for object and action for operation.

So most resources end up with the following set of possible actions:

  • create: (well obviously this is only useful for list resources eg. the tasklist of a new project)
  • read: be able to display the resource... (again there is a special thing with lists here. This only gives the right to see the list at all. When generating the list the access rights on each entry has to be checked and if there is no read right for it it should not be included in the list.)
  • update: be able to update a resource. (this makes no sense for list resources as the change when their members change)
  • delete: be able to remove a resource. (on list resources this should only be allowed if the list is empty, this is the only consistent behaviour I can think of because you can't always assume that by removing a list ii's associated members should also be removed)
  • rbac_read:
  • rbac_update:

Well, rbac assignes only roles to resources... in that case, how can I achieve per user rights for specific resources... one way would be to give every user its own role, which makes the whole concept kind of useless.

Then I could allow everyone to create new roles on demand. Then a user would create a role that allows others to view the resource and then add user to this role. This role creation could be done automatically and in the UI the user simply only adds the users that should have access to the specific action. On the other hand the user might associate an action on the resource to an existing role. thus giving, for example, all team members the right to use the according action. Again in the UI this would be a simple select from a list. Still it seems neccessary to have a suer_private role where only this one user is in and that has full access to all resource actions of each resource the user is creating...and if there is such a thing no new roles will be created when allowing others to take actions on specific resources...simply add the action to the private role of the other user. This private roles can be almost automatic. (created when user is created, removed when he is removed, etc. etc) Regarding the session...I hink it ok to use our sessions to store The resulting access rights defined by the roles the user is in. On the other hand...if we store them stere no immediate feedback is possible when one of the roles have been changed....well, maybe there is...each existing session for users that are associated with the changed role have to be updated. That is in any case better than calculating all the access right on every reqeust. So, what we have in place right now are users and sessions. Both can be extended to the needs for rbac. What we still need is a definition of resources and actions that build up a permission and roles in it self that will associate user with permissions.

nothing there to handle the request ... so leave it to the caller...

Todo:
add logging...maybe.

Definition at line 53 of file route.c.

References COMMAND_LEN, HTTP_DELETE, HTTP_GET, HTTP_POST, HTTP_PUT, httpResponse404(), httpResponseJson(), MEM_FREE, and MIN.

Referenced by applicationAdapterHttpUpdate().

57 {
58  char functionName[COMMAND_LEN + this->nprefix * 10];
59  Hash args = NULL;
60  fptr_routable function;
61 
62  char * tmp;
63  char * command;
64  size_t ncommand;
65  char * response_data;
66  HttpResponse response;
67 
68  if ('/' != request->uri[0]) {
69  /*
70  * we only support absolute paths within our
71  * application
72  */
73  return NULL;
74  }
75 
76  command = &(request->uri[1]);
77  command[0] = toupper(command[0]);
78 
79  /*
80  * find end of command
81  */
82  tmp = strchr(command, '/');
83  if (NULL == tmp) {
84  ncommand = strlen(command);
85  } else {
86  ncommand = tmp - command;
87  }
88 
89  memcpy(functionName, this->prefix, this->nprefix);
90  memcpy(&(functionName[this->nprefix]),
91  command, MIN(COMMAND_LEN, ncommand));
92 
93  /**
94  * \todo
95  * now get all arguments if we have some
96  */
97 
98  /*
99  * following the crud pattern we map the first part
100  * of the uri and the request method to according
101  * function names.
102  */
103  switch (request->method_id) {
104  case HTTP_GET:
105  args = new(Hash);
106  strcpy(&(functionName[this->nprefix + ncommand]), "Read");
107  break;
108 
109  case HTTP_POST:
110  args = request->post;
111  strcpy(&(functionName[this->nprefix + ncommand]), "Create");
112  break;
113 
114  case HTTP_PUT:
115  args = request->post;
116  strcpy(&(functionName[this->nprefix + ncommand]), "Update");
117  break;
118 
119  case HTTP_DELETE:
120  strcpy(&(functionName[this->nprefix + ncommand]), "Delete");
121  break;
122 
123  default:
124  /* other methods are not subject of REST */
125  return NULL;
126  }
127 
128  /*
129  * \todo for the moment I don't cache the found symbol...
130  * I don't even check if there was an error...the only thing
131  * I do is checking a NULL symbol and in that case don't
132  * handle the request here.
133  */
134  dlerror();
135  function = dlsym(this->handle, functionName);
136 
137  /**
138  * \todo somewhere here or above access control have to take place
139  * Default policy should be deny, anyway, there are a few resource
140  * that should be accessible even when not logged in...the are at
141  * least most of the assets as well as functions like version or
142  * sessinfo and in fact currentuse to have a way to find out that
143  * one is not logged in.
144  * In general a deny will be handled by storing an error message in
145  * some stash and then trigger a redirect to the login page.
146  * To be really rbac it seems neccessary to me to create a user
147  * "not logged in" and assign him the exceptions to the default
148  * deny policy.
149  * For the moment I assume that if there is no resource for the
150  * URL in the application it must be an asset and just return NULL
151  * indication that we still have no response for the request.
152  * Another thought... resources will be created dynamically by
153  * creating tasks or users or anything.
154  * Each of these resources may have options to admin them. This means
155  * most of the time to be able to modify them but additionally the
156  * creater of the resource might need the right to modify the
157  * rbac rules that apply to that resource.
158  * So, if I keep the real resources and their rbac configuration
159  * separated as planned it might be neccessary to give the creater
160  * of a resource the ability to modify both.
161  *
162  * So lets assume user georg creates a task that might be identified
163  * by /task/uuid(task). Then additionally an rbac resource will be
164  * created identified by /rbac_resource/uuid(/task/uuid(task)).
165  * User georg will have all rights on both resources.
166  * This means that rbac resources are resources by their own but how
167  * to control the access to these, I can't build another rbac resource
168  * and another and and and... so I think it is neccessary that every
169  * resource as it is has to hold their access in itself.
170  * The creating user will gain access to all REST operations as well
171  * as the right to change access control (which again are REST operations
172  * on these.
173  *
174  * Sidenote: I use a slightly differen naming than the ansi spec uses
175  * I the term resource for object and action for operation.
176  *
177  * So most resources end up with the following set of possible actions:
178  * - create: (well obviously this is only useful for list resources
179  * eg. the tasklist of a new project)
180  * - read: be able to display the resource...
181  * (again there is a special thing with lists here. This
182  * only gives the right to see the list at all. When
183  * generating the list the access rights on each entry
184  * has to be checked and if there is no read right for it
185  * it should not be included in the list.)
186  * - update: be able to update a resource.
187  * (this makes no sense for list resources as the change when
188  * their members change)
189  * - delete: be able to remove a resource.
190  * (on list resources this should only be allowed if the list
191  * is empty, this is the only consistent behaviour I can think
192  * of because you can't always assume that by removing a
193  * list ii's associated members should also be removed)
194  * - rbac_read:
195  * - rbac_update:
196  *
197  * Well, rbac assignes only roles to resources... in that case, how can I
198  * achieve per user rights for specific resources... one way would be
199  * to give every user its own role, which makes the whole concept kind
200  * of useless.
201  *
202  * Then I could allow everyone to create new roles on demand. Then
203  * a user would create a role that allows others to view the resource
204  * and then add user to this role. This role creation could be done
205  * automatically and in the UI the user simply only adds the users
206  * that should have access to the specific action.
207  * On the other hand the user might associate an action on the resource
208  * to an existing role.
209  * thus giving, for example, all team members the right to use the
210  * according action. Again in the UI this would be a simple select
211  * from a list.
212  * Still it seems neccessary to have a suer_private role where only
213  * this one user is in and that has full access to all resource actions
214  * of each resource the user is creating...and if there is such a thing
215  * no new roles will be created when allowing others to take actions
216  * on specific resources...simply add the action to the private role of
217  * the other user.
218  * This private roles can be almost automatic.
219  * (created when user is created, removed when he is removed, etc. etc)
220  * Regarding the session...I hink it ok to use our sessions to store
221  * The resulting access rights defined by the roles the user is in.
222  * On the other hand...if we store them stere no immediate feedback is
223  * possible when one of the roles have been changed....well, maybe
224  * there is...each existing session for users that are associated with
225  * the changed role have to be updated. That is in any case better
226  * than calculating all the access right on every reqeust.
227  * So, what we have in place right now are users and sessions. Both
228  * can be extended to the needs for rbac.
229  * What we still need is a definition of resources and actions that
230  * build up a permission and roles in it self that will associate user
231  * with permissions.
232  */
233 
234  if (NULL == function) {
235  /**
236  * nothing there to handle the request ... so leave it to the
237  * caller...
238  */
239  char * error;
240 
241  if (NULL != (error = dlerror())) {
242  /**
243  * \todo add logging...maybe.
244  */
245  }
246 
247  return NULL;
248  }
249 
250  /*
251  * function has to allocate the memory for reponse_date by using
252  * memMalloc.
253  */
254  response_data = function(this->application, sess, args);
255 
256  switch (request->method_id) {
257  case HTTP_GET:
258  delete(args);
259  break;
260 
261  case HTTP_POST:
262  case HTTP_PUT:
263  case HTTP_DELETE:
264  default:
265  /* other methods are not subject of REST */
266  break;
267  }
268 
269  if (NULL != response_data) {
270  response = httpResponseJson(response_data, strlen(response_data));
271  MEM_FREE(response_data);
272  } else {
273  response = httpResponse404();
274  }
275 
276  return response;
277 }
#define MEM_FREE(seg)
Definition: memory.h:28
#define COMMAND_LEN
Definition: route.c:49
HttpResponse httpResponseJson(const char *, size_t)
Definition: json.c:40
#define MIN(a, b)
Definition: commons.h:35
char *(* fptr_routable)(Application, Session, Hash)
Definition: router.h:43
HttpResponse httpResponse404()
Definition: 404.c:47

+ Here is the call graph for this function:

+ Here is the caller graph for this function: