Advertisement
[ This posting is the first in a series about the tribe.net application architecture. ]
Tribe.net is an application that is fundamentally built to allow for arbitrary types of user generated content. An application of this sort presents very specific security requirements to account for the fact that millions of objects may be accessed and modified by millions of people. Consider, for example, maintenance of your own personal profile. No other user but you should be able to change your profile attributes. Tribes, as another example, are application objects that require members to be able to create content for that tribe if and only if they are members of that tribe.
Taking "top-level" objects such as tribes, people, and listings into account, the programmatic challenge of assuring the correct permission controls on each object is fairly simple. Am I in the tribe? Am I the person I am trying to change? Do I own the listing I am trying to modify? What gets more tedious, and more difficult to maintain, is when those top-level objects take on more functionality, and more child objects. For example, tribes have Postings, Topics, Photos, Listings, Recommendations, and Events. In addition, people have Photos, Listings, and Recommendations. Finally, listings have Photos.
So what we end up with is lots of different objects that may reasonably live in lots of different contexts. We need to be sure that creation of this content is done only by those who may do so (i.e. those with verified accounts with permission on the top-level object) and that content that gets created cannot be spoofed and attributed to someone else, AND that existing content may not be changed by those without permission to do so. And by the way, there needs to be an administrative user who has privileges to all this stuff to anyone so that the site may be reasonably maintained from a Customer Service perspective.
The purpose of this thread is to document the Redwood architecture package that we use at tribe. Redwood is a Java-based architecture that is built on top of the Jakarta-Turbine application architecture. The purpose of Redwood is to "model the model". Many web applications these days use the Model-View-Controller (MVC) design pattern by virtue of the Open Source package they have chosen to build on. These frameworks usually provide a controller, some typical application services, and may provide some help on the view. Jakarta-Struts, for example, is MVC for the masses because it brought this pattern to the JSP world, and also provides a centralized configuration file to define screen flows in the view. Similarly, Jakarta-Turbine has provided a simple controller along with some built in service brokering functionality. The Spring framework provides all of the above and more. But none of these frameworks go to the next step and provide assistance in creating the security model that is necessary for an application like tribe, nor should they. This is a job that is typically left to application developers, and the result involves an Object-Relational mapping tool along with some layers built on top to try and automate the process of securely manipulating the application data. And those security layers that are developed do not often lend themselves to re-use across different companies and applications.
Redwood provides a method for modeling the Model of an application in an abstract way. The name "Redwood" comes from the fact that this model takes the form of a tree (an XML file). The Tribe.net tree is actually quite large now, but a subset of it looks like the following:
Application -> Person -> Photo, Interest, Listing
Application -> Tribe -> Photo, Posting, Listing
Application -> Listing -> Photo
One way to translate such a tree into English is that the Application has People, Tribes, and Listings, that Tribes have Photos, Postings, and Listings, and that People have Photos, Interests, and Listings, and that Listings have Photos. Each of these objects is a <branch> element in the XML file, and each branch contains information about how to get the underlying data that it represents, and branches that have security requirements (like People and Tribes) have configuration properties in the XML file to reflect that. But the interesting thing is that when the application wants to create, modify, or remove a particular branch on the tree, there is no code in the application. The RedwoodService and its supporting classes know how to find a branch and walk back up the tree until it finds a security credential to check. This is in fact how we do the checks for everything from creating a new tribe posting to adding a new photo to your profile. There is nothing about the Photo object specifically that checks security, it is that Photo object's position in the tree and the inherent security credentials of that position that provide us with the answers.
[ to be continued ]
Tribe.net is an application that is fundamentally built to allow for arbitrary types of user generated content. An application of this sort presents very specific security requirements to account for the fact that millions of objects may be accessed and modified by millions of people. Consider, for example, maintenance of your own personal profile. No other user but you should be able to change your profile attributes. Tribes, as another example, are application objects that require members to be able to create content for that tribe if and only if they are members of that tribe.
Taking "top-level" objects such as tribes, people, and listings into account, the programmatic challenge of assuring the correct permission controls on each object is fairly simple. Am I in the tribe? Am I the person I am trying to change? Do I own the listing I am trying to modify? What gets more tedious, and more difficult to maintain, is when those top-level objects take on more functionality, and more child objects. For example, tribes have Postings, Topics, Photos, Listings, Recommendations, and Events. In addition, people have Photos, Listings, and Recommendations. Finally, listings have Photos.
So what we end up with is lots of different objects that may reasonably live in lots of different contexts. We need to be sure that creation of this content is done only by those who may do so (i.e. those with verified accounts with permission on the top-level object) and that content that gets created cannot be spoofed and attributed to someone else, AND that existing content may not be changed by those without permission to do so. And by the way, there needs to be an administrative user who has privileges to all this stuff to anyone so that the site may be reasonably maintained from a Customer Service perspective.
The purpose of this thread is to document the Redwood architecture package that we use at tribe. Redwood is a Java-based architecture that is built on top of the Jakarta-Turbine application architecture. The purpose of Redwood is to "model the model". Many web applications these days use the Model-View-Controller (MVC) design pattern by virtue of the Open Source package they have chosen to build on. These frameworks usually provide a controller, some typical application services, and may provide some help on the view. Jakarta-Struts, for example, is MVC for the masses because it brought this pattern to the JSP world, and also provides a centralized configuration file to define screen flows in the view. Similarly, Jakarta-Turbine has provided a simple controller along with some built in service brokering functionality. The Spring framework provides all of the above and more. But none of these frameworks go to the next step and provide assistance in creating the security model that is necessary for an application like tribe, nor should they. This is a job that is typically left to application developers, and the result involves an Object-Relational mapping tool along with some layers built on top to try and automate the process of securely manipulating the application data. And those security layers that are developed do not often lend themselves to re-use across different companies and applications.
Redwood provides a method for modeling the Model of an application in an abstract way. The name "Redwood" comes from the fact that this model takes the form of a tree (an XML file). The Tribe.net tree is actually quite large now, but a subset of it looks like the following:
Application -> Person -> Photo, Interest, Listing
Application -> Tribe -> Photo, Posting, Listing
Application -> Listing -> Photo
One way to translate such a tree into English is that the Application has People, Tribes, and Listings, that Tribes have Photos, Postings, and Listings, and that People have Photos, Interests, and Listings, and that Listings have Photos. Each of these objects is a <branch> element in the XML file, and each branch contains information about how to get the underlying data that it represents, and branches that have security requirements (like People and Tribes) have configuration properties in the XML file to reflect that. But the interesting thing is that when the application wants to create, modify, or remove a particular branch on the tree, there is no code in the application. The RedwoodService and its supporting classes know how to find a branch and walk back up the tree until it finds a security credential to check. This is in fact how we do the checks for everything from creating a new tribe posting to adding a new photo to your profile. There is nothing about the Photo object specifically that checks security, it is that Photo object's position in the tree and the inherent security credentials of that position that provide us with the answers.
[ to be continued ]
Advertisement
Advertisement
-
Re: [Tribe] How tribe.net works....
Thu, January 13, 2005 - 5:44 PMThis Redwood tool sounds interesting. If only it were available on Sourceforge ;) -
-
Re: [Tribe] How tribe.net works....
Thu, January 20, 2005 - 8:18 PMhmm. That *would* be interesting...
-
-
Re: [Tribe] How tribe.net works....
Thu, January 20, 2005 - 8:28 PMRedwood Layering and Form Management
This post addresses how modeling the model impacts the process of data creation, modification, and removal in the Redwood system. As we have already discussed, the unique feature of redwood is that it provides a way for you to represent your application model as a hierarchical tree of objects, each element in the configuration corresponding to a "branch" in your application tree. In this model, any application process can be broken down into a simple series of redwood branch creations, modifications, and even removals. So in the redwood view of the world, a business process (such a boring term) boils down to creating, modifying, and removing a series of branches in the redwood tree. And as previously discussed, the framework itself is responsible for verifying that the current user has the security clearence to take those various actions. The application is also able to extend the base functionality to include any additional processing, but it is the framework that is responsible for invoking all of this.
But as we consider the process of creating and modifying application data in the web environment, the fact that we have modeled the model in the framework gives us a great opportunity to put a lot of structure into HTML forms processing that would not be possible otherwise. This structure allows us to develop new application functionality very rapidly as it puts structure into our field validation, page re-rendering, and security checking.
The layers are the following:
HTTP Parameters (servlet API stuff)
---------------------------------
Redwood Task List
---------------------------------
Redwood Task (1 or many)
---------------------------------
Redwood Data Branch (1 per task)
---------------------------------
Java Bean
---------------------------------
Database row
The first step in this process is to transform from the servlet world into the Redwood world. There is a well-defined contract (perhaps a topic for another post) that allows the front and back ends to agree on what constitutes a task, and what parameters will be bound to that task. The RedwoodTask can be thought of as a mini-request object that contains a collection of key value pairs that will ultimately end up in the database. Once the tasks have been assembled, they are then validated. Task validation can take place in the framework, or in the application if the rules are more complicated than just "not blank, length < 20".
The great thing about having the task object as a holding area between the data branch and the unstructured request object is that it can hold the values in a type-free context during validation and then pass the values through to the Java bean if validation passes, or it can be used to re-render the entered values on the page if there are validation errors. That was a mouthful, so perhaps an example of how this is applied would be useful. Consider the rent field on Tribe apartment listings. We have included this as a free-form HTML text field on the front end, but before it goes into the database we need to make sure that the user has entered a numeric value for this field. When the form is submitted, the arguments are first organized into their individual tasks. The rent value is taken from the HTTP request and dropped into the apartment task. Then, a check is done on the rent attribute of the apartment task to see if the entered string contains only numbers. If so, the task is then transformed into a Redwood Data branch, and the attributes of the task are placed into a Java bean, which lives inside of the data branch. The last thing we need to do then is actually persist the change to the database. All RedwoodTask objects contain a mode setting describing what needs to be done to the underlying data branch: create, modify, or remove, or replace. Once the databranch is populated, the correct action API is called and the database reflects the desired result of this process.
If the task object wasn't there as a go-between and we tried to dump the parameters straight into data branches, then we would get a Java Exception when trying to put letters into a numeric data type. However, you could easily argue that I could just do the validation without bothering with a task at all. The great thing about having a task object is that if the validation fails I have a place where I can put a validation error message, and the framework can then use that object to re-render the form with the valued that I typed in previously along with a message explaining the error. This way, we are able to repopulate all of the values in the page including the erroneous ones, and allow you to correct your mistake and resubmit. There are many sites on the web that do this (obviously) but the Redwood framework brings a lot of structure to it, and consequently *not* a lot of application code. We never have to worry about coding the re-population logic, or directing back to the same page on form validation errors because it is a service of the platform.
Even better, having such a structure in place allows us to implement multi-page workflows quickly and easily, and in a stateless fashion. There is enough structure in the browser-server contract that a multi-page workflow (such as the flow for creating a new listing or event) can be automatically maintained by the framework without exerting any undue stress on the developer. Of course, there is stress associated with learning how to leverage all of these features, but the result is code that does the right thing and is very compact.
And in my world, less code = less bugs!
[ next: Redwood Search (I think) ] -
-
Re: [Tribe] How tribe.net works....
Sun, January 23, 2005 - 8:04 PMI'd be curious to know more about the "contract" between browser and server in Redwood. How much does a page developer have to understand about the framework to build such forms (in other words, how well can skills be divided between page developer and application developer)? Also, how dependent is the framework on hidden fields and other client-based input, and how do you deal with badly formed (or even malicious) client requests (like, someone manipulating the HTML themselves)?
Are these posts the beginnings of documentation for an open-sourced Redwood? -
-
Re: [Tribe] How tribe.net works....
Tue, January 25, 2005 - 7:55 AMIn answer to the second question, I do intend for this documentation to be the beginnings of an open sourced redwood. The rest of this entry is a tad more technical than I had intended to get, but since you ask, here are the details. There will be more on this later.
The contract between front-end and back, and the security applied to each form submission, brings up another interesting facet of the idea of modeling the model. The basic contract involves the following (this is all given using Jakarta-velocity sytnax):
1) Set up a <form> element in your HTML, whose action is $!submitToSelf. Basically what this means is that all forms should, by default, submit to themselves. (Yet another installment will be on the Redwood screen dispatcher mechanism which allows you to conditionally choose one of many destinations for the form you submit, a la Struts).
2) Set up the action that you would like to invoke with
$redwood.setAction(<action name>)
This invocation will tell Redwood (well, Turbine actually) which action should be performed.
3) Set up the tasks for this page
$redwood.create("foo", "<task path>")
$redwood.modify("bar", "<task path>")
4) Bind HTML variables to these tasks. This is done by naming the variables foo_fieldName or bar_fieldName.
Submitting this form will cause redwood to do what was previously discussed: instantiate tasks, validate the forms, check the security of the user, and execute the tasks.
Regarding security of this stuff, there are a couple of things to keep in mind. First and most important is that a form will never be able to take an action on the back end that is not allowed by the redwood tree. So a use may mess around with the HTML to his or her heart's content, but if they change the path or mode of a task to something that is illegal (i.e. change the path to a branch that does not exist) or to something that they do not have access to (such as changing a Person id in a path to someone else) an exception will result and the action will be aborted. Security of user-generated content is after all the point of this whole thing.
So with that said, it should be pointed out that just doing pure HTML and submitting to the default action on the back end is not advisable in a production environment. For prototyping it can be a very rapid development methodology, but in practice we have found that doing too much logic in the template, and not doing any custom validation in the actions leads to code that is difficult to manage. We have not experienced security problems, at least not when things were coded correctly. -
-
Re: [Tribe] How tribe.net works....
Sun, January 30, 2005 - 4:22 PMSo, do the Velocity calls you show actually do something on the server? Or, a better way to ask that might be: is it safe to assume that as long as you can generate the proper form fields (hidden and otherwise) and the proper action in the form, you could use any "view" environment with Redwood? That is, are those Velocity calls just creating HTML that will be meaningful only as part of an HTTP POST operation, or do they actually prep some kind of listener on the Redwood side as the page itself is rendered?
You, of course, know at least part of why I ask, which is to be able to use Redwood with something like ColdFusion (or even PHP). Presumably, any page rendering environment could use Redwood as long as it understands how to create the proper HTML output to make the form variables meaningful on POST (obviously, you'd still need to build some kind of bridge for data retrieval). -
-
Re: [Tribe] How tribe.net works....
Mon, February 14, 2005 - 6:18 PM> That is, are those Velocity calls just creating HTML
> that will be meaningful only as part of an HTTP POST
> operation, or do they actually prep some kind of
> listener on the Redwood side as the page itself
> is rendered?
It is expressly forbidden for the velocity calls to set up the server side to receive a request for a very important reason. Doing so would break the statelessness of those forms since they would presumably expect to find something on the server side when they arrive after being submitted. It is critical on Tribe.net that this not be the case - our forms *must* be stateless because it is very common for people to have several tribe windows active at the same time. Rather than try to make fancy back end mappings of different forms to different state objects on the server side, we have gone the opposite way and forced forms (even multi-page flows) to be stateless.
However, the velocity calls *do* set up temporary objects during the rendering of that template on the server side that are important. Namely, a call to $redwood.modify(<token>, <path>) will retrieve the data behind that path and give the form access to the fields. This is a topic worthy of it's own separate post about the field validation setup, but here is a quick example of what this looks like in a velocity template. Let's say I want to create a form to change my name on the system. It would look something like this:
<form>
...
$redwood.modify("me", "Application[tribe].Person[myGUID]")
FIRST NAME:
<input type="text"
name="me_firstName"
value="$!redwood.me.firstName"/>
LAST NAME:
<input type="text"
name="me_firstName"
value="$!redwood.me.lastName"/>
...
</form>
Now the front end will never see the $redwood stuff, but the result will be that the current settings for my first and last name will show up in the value parameter of the text input widgets. Under the sheets, redwood will go retrieve the object named by the path and it will be available to the form during the rendering stage (on the server). This also means that you may use the exact same form to gather the data initially as well with no change to the template. It is this feature that makes redwood a bit more difficult to carry over to other presentation technologies right away. We basically need to have velocity style access to java objects in the view context in order to exploit some this feature. Other than that, it would in fact be possible to just submit a well formed redwood form and have it do the right thing on the back end. -
-
Re: [Tribe] How tribe.net works....
Mon, February 21, 2005 - 11:06 AMProbably not as hard as you might think, though you would need to create some sort of stub interface for the presentation layer of choice that made calls back to Redwood to populate the appropriate values.
I supect the code behind $redwood could be easily adapted into, say, ColdFusion -- either as custom tags or a component interface.
-
-
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 1:41 PM"Regarding security of this stuff, [...] So a use may mess around with the HTML to his or her heart's content, but if they change the path or mode of a task to something that is illegal (i.e. change the path to a branch that does not exist) or to something that they do not have access to (such as changing a Person id in a path to someone else) an exception will result and the action will be aborted. Security of user-generated content is after all the point of this whole thing."
Sounds nice in theory, but consider:
I can take an "ask friend to join" link, swap out the tribe-id with one that I'm not a member of, and the invite will go through. Your security model doesn't check that, it only checks that the inviter is a member of the tribe at accept time. (The friend can't accept and join if the inviter isn't there.) What else is there that I haven't found?
-
-
-
Re: [Tribe] How tribe.net works....
Wed, February 23, 2005 - 3:06 PMRedwood Screen Dispatching and Multi-page Workflows
[I said Redwood Search was next, but I was working with screen dispatching today and thought it a more pertinent subject]
So far we have covered what the redwood tree is for ("modeling the model") and how the different layers work together to process a form with relatively little need for additional application layer code. Another thing that always seems to be more of a pain than it should be is forwarding control to the next page in a form flow. Jakarta-Struts did a good job of this by introducing the notion of the ActionForward class. Redwood has a similar object called the RedwoodDispatcher class. A dispatcher is an object that contains many mappings between a token and its corresponding url as well as a boolean indicating whether the target URL should be redirected to rather than just forwarded to.
In addition to tracking normal dispatch mappings, the RedwoodDispatcher contains a "call stack" which is able to keep track of nesting different form flows within larger flows. This allows for very easy re-use of "sub-flows" - or flows which may be used to add the same sort of information to any of several different multipage flows. If you have ever clicked on "Change Location" from the listings creation, tribe creation, or local favorite creation flow, you have been dispatched through a redwood sub-flow. The way these flows know where to return to is by pushing the return URL onto the dispatcher call stack. This call stack is then tracked through the forms of the sub-flow, and at the conclusion of the sub-flow control is dispatched back to the mapping on top of the call stack. Other examples of this are the address book on the listings page which should someday be integrated into composing a message, and the newly revamped "re-login" flow which should will do a better job of re-establishing your timed out session in the middle of a multipage flow without losing your information.
I think that this last example is the most interesting, as it was a happy side effect of the design. I would also be interested in hearing how others out there handle this situation. Here is the process flow for handling re-establishment of your session in the middle of a flow:
1) The initial form is rendered while you are logged in, and we tag it as such right in the HTML.
2) While typing in your very well-thought-out post, you get distracted, go to lunch, or just step away for 30 minutes - and your session times out.
3) When you come back and hit submit, a new session is started on the back end.
4) If you have "remember me" checked, then your session is re-established and you go about your business. If not, a new dispatch mapping is dynamically added to your dispatcher object, the default dispatch mapping is set to the page that was just submitted, and we shunt you off to the Relogin prompt page.
5) The relogin page then has the state of the form that you just came from, and it gathers in your re-auth information. Click on Submit.
6) If your credentials pass, then you go back to the page that you initially submitted and the HTML widgets are refreshed with the values that you originally submitted (they have not yet been validated).
7) If your credentials fail you keep bouncing back and forth until you get it right. Eventually you should end up back on the form. If you log in as someone else who is not in the tribe, all of the normal back end security kicks in and you are handled just as you would be in the normal application flow. None of the database stuff happens until this last form is submitted anyway.
The best thing about a framework like this is that as long as all of your Turbine actions extend the Redwood base action, all of this functionality is automatically part of the application. As the breadth of your application grows there is no maintenance burden imposed to keep this sort of functionality intact (just as with the security features previously discussed).
On looking back on this post, it is one of my more stream of consciousness dumps on this topic, so please feel free to ask for more details where they are lacking. But basically, the summary of this thing is that in addition to offering a framework for securely gathering form data and creating new application data, redwood offers a screen dispatch mechanism that allows dynamic decision making in the midst of form processing to support multi-screen flows that have many different paths. Rather than dumping all this in a configuration file, in redwood I try to put this information more at the point of impact - in the actions and templates that are physically a part of the flow.
[ Maybe Search next?]
-
-
Re: [Tribe] How tribe.net works....
Tue, February 22, 2005 - 4:04 PMGreat stuff! Can't wait until the next installment.
-
Re: [Tribe] How tribe.net works....
Sun, February 27, 2005 - 7:36 PMNow that I have inundated you with words, I thought that I would show you a picture of what our redwood tree currently looks like. This picture, although it is a bit small to be readable, should give you an idea of the scope of the tribe.net application. Having a single document like this can be quite helpful in getting a 10,000 ft. view of a web application - it tells us at a glance the relationships between our application objects and gives insight into what people, listings, and tribes are capable of owning.
As an example of how this setup is useful, adding the blog functionality to the new pcard was simply a matter of making child branches for the articles, comments, and photos and the security issues as well as database code were automatically taken care of just by virtue of the fact that the branches are where they are in the tree.
This picture also splits the tree up into the major components: Listings, People, and Tribes.
Here is the picture:
louvre.tribe.net/tribe/upl...2859b122b6 -
-
Re: [Tribe] How tribe.net works....
Sun, February 27, 2005 - 10:34 PMIs that picture auto-generated from the XML? -
-
Re: [Tribe] How tribe.net works....
Sun, February 27, 2005 - 10:53 PMwell, sorta.
One thing that redwood does every time it boots up is to emit the contents of a DOT file. The DOT language is described in detail here:
www.graphviz.org/Documentation.php
It turns out that OmniGraffle knows how to read in DOT files, and once inside Graffle the sky is the limit. This representation of tribe.net ended up taking me quite a while to do because I had to spend a lot of time separating out all of the branches into the 3 major areas, but the hardest part of the work (namely laying out the graph of entity relationships) was done for me by the redwood XML parsing process.
-
-
Re: [Tribe] How tribe.net works....
Mon, June 13, 2005 - 5:13 PMOK, so a long time has passes since the last installment of "How tribe.net works." In the intervening time, there has been an important discovery regarding one of the important ways in which tribe.net does not work. The redwood system that I have been describing to you here is very good at "instance based" security. This means that without any code in your application, it is possible to enforce the idea that no user is able to edit another user's profile, unless they are a site administrator. Similarly, no user may add content to a tribe unless they are a member of that tribe. The tribe case, however, has exposed a flaw in this security model. In a sense, the moderator of a tribe "owns" all of the content of that tribe. His or her user privileges grant the ability to modify or delete any redwood branch under that tribe on the tree. On the surface, this sounds like the correct behavior - moderators must be able to moderate after all. However, if you form your HTML forms correctly, you can make changes to the data that were not intended by the Product designers. Specifically, you are able to change internal columns to different values.
This security hole has been interesting to think about, because it has required me to step back from the code a bit and analyze what is right and what is wrong with redwood as a core architecture package. In addition, it has brought about the "Skills Update" ( sanfrancisco.tribe.net/thread...68f0cb6 ) project that I embarked on a few weeks back. One of the products that I have been learning a lot about recently is the Spring framework, and the Inversion of Control principle that it implements. When discussing IoC, one must think about the different architectural concerns an application has, and how those concerns may be separated into independently testable units. The Redwood framework has elements of all of the following concerns included:
- Transaction Management
- Field Validation
- Generic Exception Handling
- Form Page Flow
- Authorization Checks
- Persistence and Entity Wiring
You get all of this by extending the correct base class, but it turns out that extending a base class to get it makes the resulting code very difficult to test becuase of all the dependcies underlying the individual units. Furthermore, most of these concerns have been implemented by the Spring community at least as well as I have done them myself in Redwood. All except one, the authorization checks. I would be ready to migrate to Spring tomorrow if I could only address this last piece of the puzzle. Everything other concern is accounted for very well in Spring, in a very module fashion. The IoC container provided by Spring does a great job of reducing dependencies in your code, and thus making the code far easier to unit test. However, instance based ACLs, which are critical to an application like tribe, are not yet well accounted for. So part of my skills update thread will likely contain some information about attempts to put in an instance-based ACL framework to augment Spring.
So is redwood dead? In its current form I would say that it is. The Java community has come a very long way since Redwood was first coded and 2001. Inversion of Control is now a household word (for houses full of geeks anyway) and I would not want to start a new project without an IoC container at its core. However, I did find an interesting project today that is much like redwood and may be worth more research, called Jackrabbit ( incubator.apache.org/jackrab...iew.html ). This apache incubator project implements a hierarchical content model much like redwood's, and provides some very interesting methods of retrieving that hierarchical data.
Their architecture provides an interesting view of an application as a set of code that manipulates content, wherever it may live. This was the original intent of Redwood and indeed the early implementations included FileSystemPeers for getting application data from disc instead of db, using the exact same API. The JCR (Java Content Repository) is still pretty early in its development, but it seems to embody most of the ideals that the Redwood system was build to address in the first place. I think I will be keeping an eye on that, but in the meantime finding ways to move tribe forward into a new framework that is more up to date with the Java state-of-the-art. -
-
Re: [Tribe] How tribe.net works....
Tue, June 14, 2005 - 3:15 PM"However, if you form your HTML forms correctly, you can make changes to the data that were not intended by the Product designers."
Hee. That's a fun euphemism. I don't think you've stomped out all of those bugs yet, though. I mean, really, tribe provides a post ID for me when I click 'reply', but tribe doesn't force me to use that post ID. I used "20050614-1511-4444-1337-000000000000" for this post... -
-
Re: [Tribe] How tribe.net works....
Wed, June 15, 2005 - 11:47 PMIt wasn't always like that. The only reason that I include pre-generated UUIDs in the forms is to prevent the double posting problem that plagued our product early on. There are obviously other ways that I could prevent the same form from being submitted twice. However, those approaches involve disallowing submitting the same form. In other words, I thought that the site would be more usable if people were able to just click on the browser back button, fix their mistakes, and resubmit. By including the UUID up front I am able to statelessly use the same form for creating or modifying topics and replies. Statelessness is critical for us, since people often have several Tribe windows open at once, possibly composing several tribe replies at once. I understand that one _can_ change the form, but obviously I have been naive in not assuming that one _would_ change the form.
I do appreciate your pointing these things out though. I would much rather discuss them in the open rather than find out about them in a more catastrophic manner at a later time. -
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 12:23 PMStateless is good. I ran into state problem long ago on tribe, with search, I expect it is fixed now.
Here's what you can do kill the double post problem, allow reposting to change words, and disallow random ID injecting: when you make the form earmark the ID being used as a future post slot. When you get back the form, if the ID presented has not been earmarked, don't accept the form. -
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 12:32 PMBrian and I have talked about a similar earmarking as you describe. The problem with earmarking for us is that it either includes a database write (to earmark the id in the database) or would only work on the application server from where you got the form. I don't like the idea of a superfluous database write because it's expensive, and Brian doesn't like the idea of an earmark (or ticket, as we were calling it) because if that application server were to crash you'd be load balanced to another server and lose your ticket.
What I proposed was to include a checksum or hash of the immutable fields whose calculation involved a secret key or value in each form we send out. If the form comes back and the checksum/hash doesn't match the values in the form, then we know you've tinkered with it and reject the submission. -
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 12:33 PMclarification: by immutable fields I mean those that the user shouldn't be allowed to change. -
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 1:35 PMThat's a good way of doing it, too. Makes it a lot harder for me to reconstruct the form with my posterific page (see tribe.hacks for link) for replacing a posting, since now I'd need to store the checksum.
I use very similar things with my own cgi link security, and refer to the check field as a tag. Depending on the application the tag can verify just the form elements, or form elements and time of issue. This way I can make URLs that will access something, but only for a limited amount of time. (The later tags aren't a checksum, but an encrypted block, the simpler ones are MD5 based.)
-
-
This is the maximum depth. Additional responses will not be threaded.
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 2:49 PMI don't think that we would be able to implement the time-based URLs because we have several application servers behind a load balancer. The only persistence layer between them is the database (which we don't want to write to for temporary things like this). Unless we were to implement a separate handler for these time-based URLs, we wouldn't be able to implement them across application servers.
I'm probably not using the right nomenclature because I haven't really thought about this before; when I say checksum/hash/encryption in this context I mean any value that we can calculate and put into the form based upon a private key that only we have, that prevents someone from updating the form and that checksum/tag to match the new values such that we would accept it as being the original. -
-
Re: [Tribe] How tribe.net works....
Thu, June 16, 2005 - 3:06 PMshouldn't be too hard to do this over several servers. use NTP to synchronize time on the servers and include the following information in the form:
<unique id, expiration time, hash(id, exp. time, secret key)>
the server then verifies the hash if the hash is valid it verifed that the expiration time has not passed.
on the other hand, you can disable resubmitting of posts completely and make edits explicit. this way the ID that's included in the message submit form can serve just the one purpose it needs to serve - preventing double submissions. it doesnt even have to be the actual message ID. a random number between 1 and 100,000 together with the tribe_id and thread_id should serve you well enough to prevent repeat submissions.
-
-
-
-
-
-
Re: [Tribe] How tribe.net works....
Sat, July 2, 2005 - 2:41 PMrule #1: never ever trust anything that comes from a URI or a form. easy to forget if you placed the value there to begin with, but you can't expect with certainty to get it back.
-
-
-
-