Modularity And Security In Composite JavaScript Apps - January 27, 2012 by

In one of my current apps for a client, I have an activity based security system that determines what the user is allowed to do. The trick to this system is that all of the authorization checks happen on the server, but the functionality that is being secured runs on the client, in JavaScript.

This is a bit of a problem. If I send all of the JavaScript that is uses to run any part of the system to the browser, then it’s possible that a clever user could enable it and do things they aren’t supposed to do. Of course, when they send a request back to the server, the server will verify they can do what they requested and block it… but the user should not be able to even try to do things they aren’t authorized to do, in the first place.

The solution that I’ve come up with, at a very high “functional area of the application” level, is simply not to send JavaScript to the browser if the user is not allowed to use it. This keeps me from having to do extra security checks in the browser, keeps the download for the user smaller and generally makes the app appear snappier because there is less code to run. More importantly, though, it keeps the user from being able to try things they can’t do.

Modules To The Rescue

I’m facilitating this through the use of modules in my JavaScript – both “module” as in the JavaScript module pattern, and “module” as in a packaged functional area of an application.

It’s worth noting, though, that I’m not using AMD (asynchronous module definitions), RequireJS, or any other “module” framework for JavaScript. The debate about the “right way” to do modules can rage on all it wants. I’m content with simple immediate functions and logical groupings of files while the more intelligent and invested people in the JS community figure that all out.

Each of the functional areas of my application is built in it’s own set of files. Each area has multiple files that it is composed within, but the files are grouped together for easy identification of what makes up a module. I also have an HTML template for each module which provides the needed <script> tags to include the code for that module.

Only Render What Is Needed

When I need a functional area of my site to be sent down to the user, I tell my server side template language to include the correct HTML file. For example, I’m doing this in an ASP.NET MVC application:

@{var user = (CustomPrincipal)User;}

@if (user.Can("locations/manage"))
{
    @Html.LocationManagementScripts()
}

@if (user.Can("locations/search"))
{
    @Html.LocationSearchScripts()
}
view raw
1.cshtml
This Gist brought to you by GitHub.

In this code, I’m checking to see if the current user is allowed to manage locations. If they are, the extension method “LocationManagementScripts” is called. This in turn renders the “LocationManagementScript.html” file at this point in my HTML layout. That file contains all of the <script> tags for the location management JavaScript app. In the same way, I’m checking to see if the user can search through locations, and running the same basic process if they can.

Self-Initializing Modules

When a functional module is included after passing one of these checks, it needs a way to get itself spun up and started so that it can do it’s magic. It may need to render something on to the screen. It may need to register itself with the application’s event aggregator, or any of a number of other things. This is where my Backbone.Marionette add-on comes in to play for my Backbone apps.

Marionette has an explicit concept of an “initializer” tied to it’s Application objects. When you create an instance of an Application object, you can call “app.addInitializer” and pass a callback function. The callback function represents everything that your module needs to do, to get itself up and running. All of these initializer functions – no matter how many you add – get fired when you call “app.start()”.

myApp = new Backbone.Marionette.Application();

myApp.addInitializer(function(options){
  var myView = new MyView({
    model: options.someModel
  });
  MyApp.mainRegion.show(myView);
});

myApp.addInitializer(function(options){
  new MyRouter();
  new SomeOtherView().render();
});

myApp.start();
view raw
2.js
This Gist brought to you by GitHub.

Each functional area of my application has it’s own initializer function. When a functional area has been included in the rendered <script> tags, the initializer gets added and when the “start” method is called, the modules for that functional area are fired up and they do there thing.

A Composite App, And Sub-Apps

One of the tricks to making all of this work, is that I need to have a primary “app” object that all of my modules know about. In the above example, the “myApp” object is this. Each of the modules for each of the functional areas has direct knowledge of this object and can call public APIs on it – including the “addInitializer” method.

A better example of what a module definition and initializer might look like, would be this:

// --------------------
// app.js

myApp = new Backbone.Marionette.Application();

myApp.addRegions({
  mainRegion: "#main"
});


// --------------------
// locationSearch.js

(function(myApp, Backbone){
  var SearchView = Backbone.View.extend({
    // ...
  });

  myApp.addRegions({
    searchRegion: "#search"
  });

  myApp.addInitializer(function(){
    var view = new SearchView();
    view.render();
    myApp.searchRegion.show(view);
  });
})(myApp, Backbone);


// --------------------
// index.html

<script language="javascript">
  myApp.start();
</script>
view raw
3.js
This Gist brought to you by GitHub.

In this example, I’m using the simple JavaScript module pattern to encapsulate my search functionality. I’m also providing an initializer for the module that instantiates a search view and shows it to the user using a region manager.

Each of these functional areas is basically a sub-application. Many sub-applications are used to compose a larger application and overall experience for the user. The composition of a larger application through various modules that are included / excluded based on some criteria are what really make this a composite application.

I also included the final call to “myApp.start()”, showing that I do this from my main HTML page and not from my JavaScript files. This provides a single point of entry for all of the registered modules, no matter which modules are registered. The “myApp” object really doesn’t care which modules are registered, honestly. It doesn’t need to care. It only needs to execute the initializers that happen to be present. If none are present because the user didn’t have permission to do anything, then nothing happens when this method is called and the user won’t see anything.

Security: Don’t Let Them See It If They Can’t Do It

If the security check to see if the user is allowed to use the location search feature fails, the rendered HTML won’t include the <script> tags for the “locationSearch.js” file. If this file is not sent down to the browser, then it will never register itself. If a module has not registered itself for initialization, it’s views won’t show up on the screen and the user won’t be able to try and use the feature. Further, the user won’t be able to “view source” on the page and find any stray JavaScript that they shouldn’t be able to use.

It’s Not Always That Easy

Of course there are other security concerns that are not this simple. When a functional area is closed off by authorization, it’s easy to keep things clean like this. We can compose the application at run time simply by including the right files and letting the code in those files register themselves for initialization. But when we have a functional area of the system that has finer grained authorization and permissions associated with it, things get a little more tricky.

I’m still learning and exploring this space. I have some ideas and am going to be implementing some of them soon. If anyone out there has any experience in handling finer grained security needs in JavaScript apps, I’d love to hear about it. Post links to your favorite resources for this, in the comments.

 


Los Techies

Composite JS Apps: Regions And Region Managers - December 21, 2011 by

In my previous post on Composite JavaScript Apps, I introduced a few of the high level design ideas and implementation details that I have been using in an application that I’m building. Since then, the requirements for that app have grown significantly and I’ve made more progress toward a better composite application design.

Content Swapping

My simple item management application started out with nothing more than these three regions on the screen:

NewImage

Once this was in place, though, a new requirement came along… a complex search with search results. To implement this, I needed to modify the application’s interface to swap the grid and add/edit form out and put in a search results screen instead. The idea is that when the user does a search, the main content area will show the search results. The user can then go back to the location management aspect of the app whenever they need to. After a bit of searching, I found a high level pattern that made this easy, and also realized that I had previously implemented the core of this pattern without knowing it.

Microsoft Prism: Regions and Region Managers

Several years ago, Microsoft released a framework for it’s WPF and Silverlight runtimes, called Prism. This was essentially the big composite app framework that people used to build well structured and decoupled apps in XAML. I never had a chance to use this framework directly, but I worked with a team of developers that did use it.

One of the things that I liked about what I saw in Prism was the way it used the idea of “regions” and “region managers” to compose the user interface. The gist of it is that you could define a visible area of the screen and build out the most basic layout for it without knowing what content was going to be displayed in it at runtime. Then at runtime, your application modules could register themselves to have content displayed in the various regions of the screen.

This pattern fits perfectly with the direction that my Backbone app is heading, so I decided to borrow the names and build my own version in JavaScript.

A Simple Region Manager

In Prism, a region is defined in the XAML markup. In web applications, it’s defined in HTML markup. Similarly, in XAML a region manager is code that you write in C# or other .NET languages, while a region manager in a web app is going to be JavaScript. Backbone.js provides a good separation between the markup and the code to run that markup through it’s Views, so I initially thought about going down this path for my region manager. After a bit of thinking, though, I realized that I didn’t necessarily need a Backbone view. What I really need, at the very core, is a JavaScript object that do the following:

  • Represent an existing DOM node
  • Change out the contents of that DOM node
  • Call any required rendering and initialization for content views that will be displayed
  • Call any required cleanup for content views when they are removed

What I came up with as an initial pass at handling these needs, is the following (hard coded specifically to use a “#mainregion” element from the DOM):

RegionManager = (function (Backbone, $) {
    var currentView;
    var el = "#mainregion";
    var region = {};

    var closeView = function (view) {
        if (view && view.close) {
            view.close();
        }
    };

    var openView = function (view) {
        view.render();
        $(el).html(view.el);
        if (view.onShow) {
            view.onShow();
        }
    };

    region.show = function (view) {
        closeView(currentView);
        currentView = view;
        openView(currentView);
    };

    return region;
})(Backbone, jQuery);

Does that look familiar? It certainly does to me. I’ve written this same code dozens of times and blogged about it in my Zombies! RUN! post. So, it turns out that I’ve been using what I’m now calling a “region manager” for a while – I just didn’t realize it, previously. Oh, happy day! I’m just formalizing a concept I had introduced somewhere else, instead of having to create something new and unknown. :)

Using The Region Manager

An in-depth use of the region manager has been covered in my Zombies post already. As a refresher, though, you only need to provide a Backbone view to the `show` method and the region manager will take over from there.

MyView = Backbone.View.extend({
  render: function(){
    $(this.el).html("some html contents");
    $(this.el).hide();
  },

  close: function(){
    this.remove();
    this.unbind();
  },

  onShow: function(){
    $(this.el).show(500);
  }
});

RegionManager.show(new MyView());
view raw
view.js
This Gist brought to you by GitHub.

The usual `close` method exists so we can handle our zombie problems. I’ve also added a bit more to the API that the region manager can handle, making it more robust and allowing it to handle more complex UI needs. Specifically, an `onShow` method fires on your view if you’ve provided one, just after the view’s `el` has been added to the DOM. This method will let you call into code that expects the DOM elements to exist, to manipulate them.

In this simple example, I’m using the `onShow` to fade the contents of the view in to view, using jQuery’s `.show` method and giving it a 500 milliseconds (1/2 of 1 second) time to do the fade. It’s a simple idea, but one that I’ve found is needed when using some libraries, such as the jQuery layout plugin. Again, this isn’t an idea that I came up with, either. I took this directly from my experience in working with WinForms applications. `onShow` is a standard event in the lifecycle of a Windows form, in .NET. It works well there, and it works well here in JavaScript, too.

But Wait! There’s More!

Well, maybe there isn’t anything more at this point in time. But there will be soon. As I’m traveling down the composite application path, I’m starting to extract the useful bits into a library so that I don’t have to rebuild the same things over and over again. If you’re interested in watching this grow over time, checkout my Backbone.Marionette repository on Github. It’s nearly empty at the time of writing this blog post, as it’s a work in progress. I plan on making a large announcement about it when I have more to share, sometime in the future.


Los Techies

Composite JavaScript Applications With Backbone And Backbone.Marionette - December 20, 2011 by

Although I’ve mentioned it in this blog already, and have been tweeting about it, we’ll call this the official announcement for my new Backbone.Marionette library.

Backbone.Marionette: Make your BackboneJS apps dance with a composite application structure!

Why?

Over the last … however many months I’ve been using Backbone, I’ve developed a number of opinions around building apps. I have a particular style of code that I write, with a particular set of functionality that is common through most of (if not all of) my apps. Backbone.Marionette is another of the many plugins I’ve created, that encapsulates my opinions.

To date, i have the following libraries for Backbone, with more ideas in my head based on the work I’m currently doing:

My goal with these plugins is not to say “this is how you must work with Backbone”. Rather, I want to provide options and opinions for those that are running into the same problems that I’ve run into. When I find myself solving the same problem over and over again, I find myself wanting to extract the solution into a library. This lets me get on with my real application development instead of focusing on solving the same problem again.

The trick with my plugins, is to provide a set of libraries that all work independently, but can be combined in very creative ways to create some even more amazing. Even within each library, I’m trying to take an approach that allows you to use only the parts that you want. Of the three plugins I’ve written, I think ModelBinding is the most restrictive / hand-holding. Memento and Marionette both offer a great deal of freedom and flexibility vs the configurability of ModelBinding.

What?

Marionette is a library of tools that you can use when you want to, without being forced to use every single piece of it. These tools include:

  • Application initialization
  • View management
  • Event aggregation

Though the number of pieces is currently small, each of these pieces is very flexible and can be used without requiring any other piece. They can also be integrated into existing applications as-needed, allowing you to migrate an app from your existing code to Marionette.

How: Application Initialization

This was the big piece for me in building Marionette. I noticed that at some point that my BackboneJS applications tend to gather a cruft of procedural mess in an “application object”. This application object has always been responsible for starting up the various bits of the app: routers, initial views, instantiating collections and initial models, etc.

The problem is that these objects have usually ended up in a giant tangled mess with far too many concerns. For example, here’s some code from an image gallery that I wrote a few months ago. Note that this is only the application startup code:

ImageGallery.App = function(initialImages){
  var vent = _.extend({}, Backbone.Events);

  var images = new ImageGallery.Images(initialImages, {
    vent: vent
  });

  var mainView = new ImageGallery.MainView();

  var controller = new ImageGallery.Controller(images, mainView, vent);

  var router = new ImageGallery.Router({
    images: images,
    mainView: mainView,
    controller: controller
  });

  var showImage = function(image){
    controller.showImage(image);
    router.navigate("/image/" + image.id);
  }

  vent.bind("image:selected", showImage, this);
  vent.bind("image:edit:cancelled", showImage, this);
  vent.bind("image:edit:saved", showImage, this);
  vent.bind("image:deleted", function(){
    controller.home();
  });

  vent.bind("image:add", function(){
    controller.addImage();
    router.navigate("/add");
  });

  vent.bind("image:next", images.next, images);
  vent.bind("image:previous", images.previous, images);

  vent.bind("image:edit", function(image){
    controller.editImage(image);
    router.navigate("/edit/" + image.id);
  });

  this.initialize = function(){
    var imageListView = new ImageGallery.ImageListView({
      collection: images
    });
    $("#image-list").html(imageListView.render().el);

    new ImageGallery.MenuView({
      vent: vent
    });

    Backbone.history.start();
  }
}

view raw
gallery.js
This Gist brought to you by GitHub.

It’s a giant mess and it’s difficult to understand and maintain.

The solution involved recognizing that I was putting far too many concerns into a single place, combined with a healthy dose of encapsulation. I want each functional area of my application to have it’s own start up code, encapsulated within that functional area’s code. I don’t want to have to mash all the functional areas together into one procedural mess. So, I build the `Backbone.Marionette.Application` object.

This object provides a number of different features, one of which is the ability to register application initialization callbacks. To do this, you need to create an instance of an Application object, first. Then call the `addInitializer` method and provide a callback function. The initialization functions are then kicked off when you call the `start` method on your application:

// create your application instance
MyApp = new Backbone.Marionette.Application();

MyApp.addInitializer(function(){
  // do stuff here, to kick off your application
});

MyApp.addInitializer(function(){
  // more start up stuff here
});

// run all of the initializers!
MyApp.start();

You can optionally pass an object through the start method, as well. This object is made available to all of the initializer callbacks as a single parameter to the callback function. Additionally, there’s a “initialize:before” and “initialize:after” event that the application object raises, using Backbone’s Event functionality.

The trick is to keep your code organized and put your initializers next to the code that they initialize. Don’t just cram all of your initializers into a single file, recreating the same mess from my image gallery. Put your initializers near the code that they initialize. Keep them separate, keep it clean and decoupled. Add as many initializers as you need. Just remember that you have no guarantee of the order in which they run.

For more info on the application object, see the documentation.

How: Event Aggregation

The `Application` object comes with an event aggregator built into it. You can call the `.vent` property of any Application instance and have full access to the Backbone Event system. I won’t go into any more detail about this right now, as you can read up on the basics of how I use event aggregators in my previous blog post.

Of course you can still build your own event aggregator with one line of code.

var vent = _.extend({}, Backbone.Events);
view raw
vent.js
This Gist brought to you by GitHub.

In fact, this is all I’m doing in the Application object. I just put it there as a convenience so I don’t have to create one manually for every app:

How: View Management

In one of my recent blog posts on composite JS apps I talked about the use of a region manager, and the code that I wrote in that post has been migrated into Backbone.Marionette as the `RegionManager` object.

The intent and purpose of a RegionManager is the same as I’ve previously talked about. The difference in Marionette is how you access a RegionManager. You have two options: use the `addRegions` method on your Application instance, or manually create a RegionManager object. The choice gives you flexibility, allowing you to use a RegionManager without using the rest of Marionette, if you want to.

The `addRegions` method on the Application object accepts a single parameter of a JavaScript object literal. The keys for this object become the names of the regions, and the value of each key should be a jQuery selector that points to the HTML DOM element that your region manager will manage:

MyApp.addRegions({
  navigationRegion: "#navigation",
  mainRegion: "#main-content"
});
view raw
region.js
This Gist brought to you by GitHub.

You can also pass a RegionManager definition as a value. See the documentation for more info on this.

Once the application is started, each of the keys that specified will be available on the application object instance. You can then call the `show` method on your region managers to show your Backbone views in that region.

Documentation And Source Code

I’ve linked to the documentation several times, which is found on the Github repository that houses the code:

http://github.com/derickbailey/backbone.marionette

I also have the annotated documentation that I’ve previously talked about, available at:

http://derickbailey.github.com/backbone.marionette/docs/backbone.marionette.html

BBCloneMail: A Reference Application

In addition to the source code and documentation, I’m building a sample application that can be used as a reference for building Backbone applications with Backbone.Marionette. The name “BBCloneMail” comes from the idea of a “Backbone clone of GMail” to demonstrate a composite application. Though it’s styling is different than Gmail’s, you can clearly see the influence in the layout, the use of categories (labels) and the drop list to switch between the mail and contacts apps.

You can find BBCloneMail online at:

http://bbclonemail.heroku.com

The source code is here:

http://github.com/derickbailey/bbclonemail

And the annotated source as documentation is here:

http://derickbailey.github.com/bbclonemail/docs/bbclonemail.html

But Wait! There’s More!

This is the first official release of Backbone.Marionette: v0.1.0… I expect the functionality to continue to grow and evolve as I use it in more application, and as (hopefully) I see other people using it and contributing their own needs to the code.


Los Techies