views:

1495

answers:

5

Hi all,
I am planning to use Ext JS for a large application. The application's features are role based. When user login, they only see menu and screen features related to them. My server side technology will be Java & JSP.

To solve this I have two ideas..
1. Create Ext JS related javascript dynamically after the user login using server side technology. The servlet / JSP will create the necessary est js code according to user roles.

2. Have Js variables that are set in view JSPs that will be used to ensure only the right features are available to users.

What is the best way to ensure security and provide role based UI in Ext Js application.
Thanks in advance for you ideas..

Abdel Olakara

A: 

First option -- Any person with Firebug and basic know-how can bypass any JS-based security.

bmoeskau
I agree.. so what solution do you use?
Abdel Olakara
A: 

Always enforce server side security, hiding controls in the frontend it's not enough.
EDIT
On the client side? well, you can follow any of the advices in the other responses, but the true is that the user can execute arbitrary javascript, modify the page's DOM and do whatever request he want.

rodrigoap
Server side security is already there.. but how to enforce on the client side?
Abdel Olakara
A: 

Don't bring functionality to the client that the user is not allowed to see. You can load js files dynamically, but your app server must enforce your rules; no role, no JS.

  var jsFile = document.createElement('script');
  jsFile.setAttribute( "type", "text/javascript" );
  jsFile.setAttribute( "src", 'someFileName.js' );
  document.getElementsByTagName("head")[0].appendChild(jsFile);

You can use an LDAP or a simpler server-side solution, but (again) don't serve JS to users who have no right to it. On the client, check for the existence of a class (during development create one class per JS file), and do not attempt to create an object when its class is not loaded.

Upper Stage
+5  A: 

I had to solve a similar problem in an application that I currently developed, but permissions are based on user country.

I know you already are, but just to reiterate for the benefit of anyone reading, permissions should always be implemented on the server side and JavaScript security is always secondary. This is because anyone with half a brain can use either a bookmarklet or Firebug to execute arbitrary JavaScript and circumvent your client-side security.

I've found that there are several ways to do this, but there are two approaches in particular that are the most sane. Regardless of the approach, there are two things to consider: 1) what JavaScript to server and how to avoid serving unnecessary logic, and 2) how to avoid executing logic that is not available to the user.

Lazy loading and permissions configuration:

  1. All widgets in my application are lazy loaded via dojo.require, so there was no need to worry about the unnecessary inclusion of JavaScript that wasn't applicable to the user. I am not deeply familiar with the ExtJs library, but as far as I have seen, it doesn't supply a comparable method; however, it is essential a synchronous ajax call followed by an eval. In any case, in this method it is important that component functionality doesn't cross-cut through different files (also, this is generally good design). Each file should be its own class that controls a specific widget or other UI element.

  2. I then set permissions in a server generated JavaScript config class. This class can then be referenced throughout the application for what is and what is not allowed.

For example, the following method controlled access to most of the widgets that were available from global controls.

com.project.frontController.prototype.init = function(widgets) {
   var permissions = com.project.config.permissions;

   // For each widget in the controller
   for ( var i=0, l=widgets.length; i<l; ++i ) {
       // If access is restricted to the widget (by id), then disable it.
       if ( !permissions[ widgets[i].id ] {
           com.project.util.disable(widgets[i].btnAccessNode);
       }
       // Otherwise, leave it enabled and connect the necessary event handlers.
       else {
           // connect an onclick handler or whatever is required for the widget
       }
   }
};

And the config looked something like:

com.project.config.permissions = {
    "widgetAbc": {
        btnAccessNode:     "#some-css-selector",
        otherWidgetConfig: "etc"
    },
    "widgetXyz": {
        btnAccessNode:     "div.some-css-selector"
    }
};

Compile and functionality check:

  1. Some applications will compile all of its JavaScript into one file, and then serve it to the client. If your application does such a thing, and you can manage to do this dynamically, all necessary JS can be determined on the server-side before it is served. Of course, this will accrue some overhead; however, you can cache compiled versions by role. If the roles are few, then this cache can be easily primed and it's just a matter of including one specific script.

  2. Since only the allowed JavaScript will be available, simply detecting if the required class/function is available before attempting to execute it is all you need to do for your permissions check.

For example, you script inclusion may look like this:

<script type="text/javascript" src="/js/compiler.php?role=moderator"></script>

And your functionality check would be something like this:

com.project.frontController.prototype.init = function(widgets) {
   // For each widget in the controller
   for ( var i=0, l=widgets.length; i<l; ++i ) {
       // If the widget controller doesn't exist, disable it.
       if ( !com.project.util.widgetExists[ widgets[i].id ] {
           com.project.util.disable(widgets[i].btnAccessNode);
       }
       // Otherwise, leave it enabled and connect the necessary event handlers.
       else {
           // connect an onclick handler or whatever is required for the widget
       }
   }
};

or

com.project.someWidget.prototype.launchOtherWidget = function() {
    if ( typeof otherWidget != "undefined" ) {
        (new otherWidget()).open();
    }
};

Notice that both methods are very similar in implementation. I would say the best way to make a determination between the two is to consider the size of your codebase, the tools available to you for compiling on the fly, and caching those role-based, compiled packages. For my project, not only was a compiler not available in the environment, but the code base was large (1.3mb inflated/296kb defaulted plus the dojo library), which wasn't acceptable as the client was more interested in maintaining low application load times.

Justin Johnson
Glad that was helpful. I'd be interested to know which method you end up using.
Justin Johnson
A: 

At our company, the jsp loads a configuration object that was created by the server based on the role of the current user. The client side then renders according to that configuration.

It is true that it could be hacked so that the initial object pretends to have more rights than it actually does; however, the hacker would get a security violation on the server when trying to do something he's not allowed to. So basically, the client side logic that applies security is just for the user's benefit, so he doesn't see more than he can. The server side checks (when an action is requested) is what actually enforces security.

Juan Mendes