{"id":2072,"date":"2011-10-04T13:15:07","date_gmt":"2011-10-04T21:15:07","guid":{"rendered":"http:\/\/blog.mozilla.org\/webdev\/?p=2072"},"modified":"2011-10-04T13:43:13","modified_gmt":"2011-10-04T21:43:13","slug":"meet-the-larpers","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/","title":{"rendered":"Meet the LARPERs"},"content":{"rendered":"<p>With the launch of our <a href=\"http:\/\/mozillians.org\">Mozillians.org community phonebook<\/a>, I wanted to talk about it\u2019s unusual data access model.<\/p>\n<h3>Typical Web Apps<\/h3>\n<p>Most web applications use a <strong>single shared authentication<\/strong> account to access data.<\/p>\n<p>Users authenticate to the site as themselves, but the web app has business logic to control who sees what from the database. The code has a shared username, say <code>web-rw<\/code> and a shared password to connect to a MySQL database.<\/p>\n<p>With the phonebook, we want to eventually support fine-grained privacy controls, much like G+ Circles or Facebook Profile settings. Profile information is sensitive, as we will eventually add t-shirt size, home address, etc. These details should be given out only to trusted groups within the phonebook; not every phonebook user, nor the public.<\/p>\n<p>Gerv chose <a href=\"www.openldap.org\">OpenLDAP<\/a> as the backend data store, for its ability to provide fine-grained permissions through it\u2019s Access Control List (ACL) feature. <strong>Instead of a shared credential<\/strong>, we <strong>connect<\/strong> to the LDAP directory <strong>as the user on every request<\/strong>.<\/p>\n<h3>Enter LARPER<\/h3>\n<p><a href=\"http:\/\/www.flickr.com\/photos\/bneumann\/3682531348\/\" title=\"LARP Life Action Role Playing by virginsuicide photography, on Flickr\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg\" width=\"500\" height=\"375\" alt=\"LARP Life Action Role Playing\" style=\"float: left\"><\/a><\/p>\n<blockquote style=\"float: right; width: 220px; font-size: 1.5em\"><p>So what does this have to do with my favorite Saturday pastime &#8211; <a href=\"http:\/\/en.wikipedia.org\/wiki\/Live_action_role-playing_game\">LARPing<\/a>?<\/p><\/blockquote>\n<p><br style=\"clear: both\" \/><\/p>\n<p>To make this all work, we had to roll our own data access model: <strong>L<\/strong>DAP <strong>A<\/strong>uthentication for <strong>R<\/strong>esources <strong>P<\/strong>er <strong>E<\/strong>ach <strong>R<\/strong>equest aka LARPER.<\/p>\n<p>A typical usage looks something like this:<\/p>\n<pre><code>\r\nfrom larper import UserSession\r\n\r\ndef search(request):\r\n   ...\r\n   directory = UserSession.connect(request)\r\n   results = directory.search(query)\r\n   return jingo.render(request, 'search.html', dict(people=results))\r\n<\/code><\/pre>\n<p>Under the covers, LARPER manages LDAP connections, binding, marshaling results into person objects etc.<\/p>\n<h4>Breaking Modern Frameworks<\/h4>\n<p>Django and many modern web app frameworks assume a shared authentication model to the database. They totally break when we want to do <strong>per user per request access<\/strong>. Connection pooling, API design, etc are hosed. At best these frameworks support a limited set of connection credentials, but they do not support a per-user database connection model.<\/p>\n<p>So why would we go against the grain and inflict so much pain onto ourselves?<\/p>\n<h5>Defense in Depth<\/h5>\n<p>If there is a bug in our web application code, we are less likely to leak data since the database itself is handling ACL. This responsibility lies in the data store, instead of the middleware.<\/p>\n<h5>Modularity<\/h5>\n<p>Our OpenLDAP server \u201cslapd\u201d has a single config file for managing the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Access_control_list\">Access Control List<\/a>. This ACL config file is a clean, single, clear place to capture static authorization rules.<\/p>\n<h5>ORM DoesNotWant<\/h5>\n<p>A last reason we need a new layer is that Django has an object\/relational mapping model. We don\u2019t need this since LDAP directories are already object oriented and not relational data.<\/p>\n<p>Okay, LARPing is not all rainbows and unicorns&#8230;<\/p>\n<h4>Leaky Abstractions<\/h4>\n<p>There are some cracks in LARPER, which may be ironed out over time.<\/p>\n<h5>Shared Authentication Credentials<\/h5>\n<p>Okay, I lied. There are several non-user accounts:<br \/>\n* LDAPAdmin &#8211; Can delete an account<br \/>\n* regAgent &#8211; Can create a new account<br \/>\n* replicationAgent &#8211; Read only access to everything in the directory for replication<br \/>\n* monitor &#8211; Useful for operations agents to monitor server health<\/p>\n<p>We\u2019ve tried hard to keep \u201cadmin\u201d type accounts to a minimum. Actions like vouching, inviting others, etc are done via LARPER as the current user, but this does break down in terms of some tasks. Do you give these capabilities to a set of users? Whom? How do you get that first user into the system? Who vouches this first user? etc.<\/p>\n<h5>Metrics<\/h5>\n<p>We have web analytics, but to get deep community metrics, we\u2019ll need access to some aggregate information. For now we\u2019re keeping a copy of some data in MySQL to be aggregated and analyzed.<\/p>\n<h5>Code Paths without a Request<\/h5>\n<p>There are places in the code where Django\u2019s framework doesn\u2019t make the current request available, so we don\u2019t use the LARPER abstraction. We can patch these cracks in the future.<\/p>\n<h5>Performance and Scalability<\/h5>\n<p>A LARPER style architecture is inherently harder to optimize. Breaking Django\u2019s assumptions, we don\u2019t get its optimizations for free either.<\/p>\n<p>Examples:<\/p>\n<ul>\n<li>One cannot blindly use caching and connection pooling from the web app layer to the data storage layer<\/li>\n<li>We cannot rely on Django style connection pooling, nor create a pg_bouncer style pool, but must instead create a per-user connection pool<\/li>\n<li>Caching must include the current user as part of the cache key, so that we don\u2019t accidentally leak data to be only be seen by User A into the view of User B<\/li>\n<p>Currently profile images are checked against OpenLDAP ACL before being sent to the client. This is being discussed as a product decision, but again has performance ramifications in multiple tiers of the application (Cache vary on Cookie, etc).<\/p>\n<p>We think the extra expense and difficulties are worth the cost, given the privacy and security requirements of a phonebook application.<\/p>\n<h4>Is LARPing Right for Me?<\/h4>\n<p>The next time you look at storing user data, it&#8217;s worth re-evaluating shared credentials to access the data.<\/p>\n<p>Like all of our code, the <a href=\"https:\/\/github.com\/mozilla\/mozillians\/tree\/master\/apps\/larper\">larper module<\/a> is open source. Today it is not abstract enough to reuse directly. It may serve as an example of how to push ACL down into your data store, or how to use LDAP and django without using the django-ldap ORM library.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With the launch of our Mozillians.org community phonebook, I wanted to talk about it\u2019s unusual data access model. Typical Web Apps Most web applications use a single shared authentication account to access data. Users authenticate to the site as themselves, &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/\">Continue reading<\/a><\/p>\n","protected":false},"author":119,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53,666],"tags":[],"coauthors":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Meet the LARPERs - Mozilla Web Development<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Austin King\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/\",\"url\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/\",\"name\":\"Meet the LARPERs - Mozilla Web Development\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg\",\"datePublished\":\"2011-10-04T21:15:07+00:00\",\"dateModified\":\"2011-10-04T21:43:13+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/b3090d13ff3b5ebf995ba12f529cce21\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage\",\"url\":\"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg\",\"contentUrl\":\"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/webdev\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Meet the LARPERs\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/#website\",\"url\":\"https:\/\/blog.mozilla.org\/webdev\/\",\"name\":\"Mozilla Web Development\",\"description\":\"For make benefit of glorious tubes\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.mozilla.org\/webdev\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/b3090d13ff3b5ebf995ba12f529cce21\",\"name\":\"Austin King\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/image\/e48c319790d7cbf429d9e8f97f590cb1\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/4a031c81db087774e3c1ecfb4b588fc0?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/4a031c81db087774e3c1ecfb4b588fc0?s=96&d=mm&r=g\",\"caption\":\"Austin King\"},\"description\":\"aka Ozten is a Seattle-based programmer working with the Identity team.\",\"sameAs\":[\"http:\/\/ozten.com\"],\"url\":\"https:\/\/blog.mozilla.org\/webdev\/author\/akingmozillacom\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Meet the LARPERs - Mozilla Web Development","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/","twitter_misc":{"Written by":"Austin King","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/","url":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/","name":"Meet the LARPERs - Mozilla Web Development","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/webdev\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage"},"image":{"@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage"},"thumbnailUrl":"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg","datePublished":"2011-10-04T21:15:07+00:00","dateModified":"2011-10-04T21:43:13+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/b3090d13ff3b5ebf995ba12f529cce21"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#primaryimage","url":"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg","contentUrl":"http:\/\/farm3.static.flickr.com\/2565\/3682531348_f243066262_d.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/webdev\/2011\/10\/04\/meet-the-larpers\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/webdev\/"},{"@type":"ListItem","position":2,"name":"Meet the LARPERs"}]},{"@type":"WebSite","@id":"https:\/\/blog.mozilla.org\/webdev\/#website","url":"https:\/\/blog.mozilla.org\/webdev\/","name":"Mozilla Web Development","description":"For make benefit of glorious tubes","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.mozilla.org\/webdev\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/b3090d13ff3b5ebf995ba12f529cce21","name":"Austin King","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/webdev\/#\/schema\/person\/image\/e48c319790d7cbf429d9e8f97f590cb1","url":"https:\/\/secure.gravatar.com\/avatar\/4a031c81db087774e3c1ecfb4b588fc0?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4a031c81db087774e3c1ecfb4b588fc0?s=96&d=mm&r=g","caption":"Austin King"},"description":"aka Ozten is a Seattle-based programmer working with the Identity team.","sameAs":["http:\/\/ozten.com"],"url":"https:\/\/blog.mozilla.org\/webdev\/author\/akingmozillacom\/"}]}},"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/posts\/2072"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/users\/119"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/comments?post=2072"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/posts\/2072\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/media?parent=2072"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/categories?post=2072"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/tags?post=2072"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mozilla.org\/webdev\/wp-json\/wp\/v2\/coauthors?post=2072"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}