Thoughts on Securing an Application

147 views
Skip to first unread message

@CapedCoder

unread,
Apr 9, 2012, 9:27:18 PM4/9/12
to framew...@googlegroups.com
Hi All,
 
I'm looking for some feedback on implementing security in my application.
 
What I was thinking of doing is adding an annotation of permissions="myrole" to those methods I want to secure in my controllers.  I would then extend each of my controllers that have "secure" methods with a base controller in which the before() method would inspect the metadata for the method in the cfc that I am calling e.g. startManageArticles.  If the particular method has a "permissions" property it would compare that property against their array of permissions and redirect them to another page if it does not exist.  The only caveat I have found is that if I want my target controller to have a before() function, I have to call super.before(rc) in order to enforce the security.  I have tested this and it does work, but I'm not sure if it is good practice.
 
I'm interested in hearing how other folks have addressed this common problem and whether or not this may be a good way to solve this problem. 
 
Thanks!
 
Seth
@capedcoder
 
 

Nathan Strutz

unread,
Apr 9, 2012, 10:35:17 PM4/9/12
to framew...@googlegroups.com
Seth,
I was thinking of doing something much like that, implicit security like you are architecting there. The idea was to make it somewhat like the fusebox circuit & fuseaction security, but *better* (somehow), and open source and in a no-configuration FW/1+DI/1 manner. I got about 10% into the design of it and then gave up because I was quickly getting so generic that I architecture-astronauted myself well past our arm of the Milky Way. Then I ran out of time.

I guess you can just take that as a "don't think too hard about it" kind of thought. Get it done first. You can iron it out later.

"...while you're programming, you are learning. It's often the case that it can take a year of programming on a project before you understand what the best design approach should have been." Martin Fowler (http://martinfowler.com/bliki/TechnicalDebtQuadrant.html)


I hate to think I'm all talk though. Practical advice now. Your design is great. consider the permission/role annotation at the component as well as the individual function level. Also, what of the performance hit to getMetaData/getComponentMetaData? I heard it was significant but I don't know if that was the CF6 days or what. Also what if you write out permission="admin" instead of permissions="admin" - that is an obnoxious bug to find! Just something to think about.

As for being practical about your architecture, being forced to remember to call super.before() is not a terrible thing - a fairly easy bug to catch. If you were to implement your security cfc as a composed object (as opposed to inherited), the design would certainly be clunkier - if you think of your controllers as a type-of controller (even though FW/1 doesn't require you to extend anything), and a security enhanced controller is a type-of that, it sounds like overall you really do have the right way to do it.

nathan strutz
[www.dopefly.com] [hi.im/nathanstrutz] [about.me/nathanstrutz]


@capedcoder
 
 

--
FW/1 on RIAForge: http://fw1.riaforge.org/
 
FW/1 on github: http://github.com/seancorfield/fw1
 
FW/1 on Google Groups: http://groups.google.com/group/framework-one

Seth Johnson

unread,
Apr 9, 2012, 11:18:14 PM4/9/12
to framew...@googlegroups.com
Nathan,

Thank you so much for your feedback.  I have found that security is often a difficult thing to abstract because each application has different requirements.  I have a similar noble goal to yours, make a generic way to lock down any FW/1 app the way I used to with FB. If you wanted to have a user/permission/group management system (e.g. Tom Nunamaker's http://www.toshop.com/fusebox/securitymodel/) and assign rights that way you could, or you could just assign an array of static rights to specific user types when they log in and it would just get out of the way and work.

I am unsure of the performance implications of using getMetaData() to squeeze the permissions attributes out of the cfc, but testing on my local machine it seems very fast (then again what isn't when you have the horsepower we have now in these machines).  Here is the method I am using in the base controller, but perhaps there is a more performant way to do it.  

Thanks again!

Seth

function before(rc)
{
var permissions = '';
var mymethod = 'start' & listLast(rc.action,'.');
var functionMd = getMetadata(this)['functions'];
for (i=1;i lte arrayLen(functionMd);i++)
{
if (functionMd[i]['name'] eq mymethod)
{
if (structKeyExists(functionMd[i],'permissions'))
{
permissions = functionMd[i]['permissions'];
break;
}
}
}
if (len(permissions) and !arrayContains(session.user.rights,permissions))
{
rc.message = 'Sorry, this area is above your pay grade.';
variables.fw.redirect('security','message');
}
}

Nathan Dintenfass

unread,
Apr 9, 2012, 11:23:36 PM4/9/12
to framew...@googlegroups.com
The one concern I'd have before locking into this scheme is that
you're setting up a world where there is a one-to-one relationship
between a controller action and your security model. It may be that as
you go you find that a single controller method is used in different
authentication contexts (by different user types in different ways).
If you have good reason to believe that won't be case or are
comfortable just baking in that assumption then seems fine, on face.

In general, I think going with meta data should save you a decent
amount of coding, but in this case I'm not sure it really does -- you
still need to type in the roles and the extra attribute, which isn't
less code to maintain than just calling a method from your base
controller to secure a given controller action. You DO get the
benefit of automatic documentation and a tight idiom, so those might
be good enough reasons in your case.

Be sure to cache the meta data in the init() of your base controller,
so you're not incurring the overhead of that every time you want to
look it up.

I find that I now always use a baseController for all of my
controllers -- it's quite slim in most cases, but it has been nice to
be able to have some utility methods always available (and I grab a
lookup of my services in the init, so I can reference them in my
controller methods as simply "services.myService.myMethod(myArgs)"
instead of calling out to the bean factory every time), so remembering
to do the super.before(rc) doesn't seem too onerous.

As an aside, I've been thinking about what a "plugin" system for FW/1
would look like lately, and this might be an interesting candidate --
basically a way to, by convention, have your machinery called as part
of the before()/init() of a controller call. I've been building a
bunch of "small" apps lately, and all of them have basically the same
user/permissions setup and some basic utilities for doing things like
bootstrapping various versions of the app as it goes through
deployments -- but I end up copying/pasting a lot of that into the
various nooks and crannies of FW/1 instead of having it all as a nice
bundle of code. Subsystems don't quite work for this kind of thing
from my initial noodling, though.

- Nathan Dintenfass

On Mon, Apr 9, 2012 at 6:27 PM, @CapedCoder <cfx...@gmail.com> wrote:

James Holmes

unread,
Apr 9, 2012, 11:40:31 PM4/9/12
to framew...@googlegroups.com
If that's the case, the functionality could easily be re-factored out into either a private method or (IMO, preferably) a service. Thin controllers are often better anyway.

--
Shu Ha Ri: Agile and .NET blog
http://www.bifrost.com.au/

@CapedCoder

unread,
Apr 9, 2012, 11:54:28 PM4/9/12
to framew...@googlegroups.com
Excellent idea on caching the metadata, that should negate a great deal of the performance impact I would expect.  You're absolutely right about locking into a particular model for security.  We all know that once our employers find out what kind of rock stars we are they want us to continue expanding the applications beyond what they originally intended (and often they change them before we're even done).  I have experimented with a variety of methods, most of which seem to become extremely verbose eventually as you add additional conditional logic (remember, you're a rock star).  Currently I am just looking to lock down bits and pieces of a custom CMS system, I doubt it will expand much further than that but it would be job security if it does.  It would be great to put together a common security plugin for FW/1 so that we all don't have to reinvent the wheel. 
 
Seth

 - Nathan Dintenfass

On Mon, Apr 9, 2012 at 6:27 PM, @CapedCoder <> wrote:
> Hi All,
>
> I'm looking for some feedback on implementing security in my application.
>
> What I was thinking of doing is adding an annotation of permissions="myrole"
> to those methods I want to secure in my controllers.  I would then extend
> each of my controllers that have "secure" methods with a base controller in
> which the before() method would inspect the metadata for the method in the
> cfc that I am calling e.g. startManageArticles.  If the particular method
> has a "permissions" property it would compare that property against their
> array of permissions and redirect them to another page if it does not
> exist.  The only caveat I have found is that if I want my target controller
> to have a before() function, I have to call super.before(rc) in order to
> enforce the security.  I have tested this and it does work, but I'm not sure
> if it is good practice.
>
> I'm interested in hearing how other folks have addressed this common problem
> and whether or not this may be a good way to solve this problem.
>
> Thanks!
>
> Seth
> @capedcoder
>
>
>
> --
> FW/1 on RIAForge: http://fw1.riaforge.org/
>
> FW/1 on github: http://github.com/seancorfield/fw1
>
> FW/1 on Google Groups: http://groups.google.com/group/framework-one

 - Nathan Dintenfass

On Mon, Apr 9, 2012 at 6:27 PM, @CapedCoder <> wrote:
> Hi All,
>
> I'm looking for some feedback on implementing security in my application.
>
> What I was thinking of doing is adding an annotation of permissions="myrole"
> to those methods I want to secure in my controllers.  I would then extend
> each of my controllers that have "secure" methods with a base controller in
> which the before() method would inspect the metadata for the method in the
> cfc that I am calling e.g. startManageArticles.  If the particular method
> has a "permissions" property it would compare that property against their
> array of permissions and redirect them to another page if it does not
> exist.  The only caveat I have found is that if I want my target controller
> to have a before() function, I have to call super.before(rc) in order to
> enforce the security.  I have tested this and it does work, but I'm not sure
> if it is good practice.
>
> I'm interested in hearing how other folks have addressed this common problem
> and whether or not this may be a good way to solve this problem.
>
> Thanks!
>
> Seth
> @capedcoder
>
>
>
> --
> FW/1 on RIAForge: http://fw1.riaforge.org/
>
> FW/1 on github: http://github.com/seancorfield/fw1
>
> FW/1 on Google Groups: http://groups.google.com/group/framework-one

 - Nathan Dintenfass

On Mon, Apr 9, 2012 at 6:27 PM, @CapedCoder <> wrote:
> Hi All,
>
> I'm looking for some feedback on implementing security in my application.
>
> What I was thinking of doing is adding an annotation of permissions="myrole"
> to those methods I want to secure in my controllers.  I would then extend
> each of my controllers that have "secure" methods with a base controller in
> which the before() method would inspect the metadata for the method in the
> cfc that I am calling e.g. startManageArticles.  If the particular method
> has a "permissions" property it would compare that property against their
> array of permissions and redirect them to another page if it does not
> exist.  The only caveat I have found is that if I want my target controller
> to have a before() function, I have to call super.before(rc) in order to
> enforce the security.  I have tested this and it does work, but I'm not sure
> if it is good practice.
>
> I'm interested in hearing how other folks have addressed this common problem
> and whether or not this may be a good way to solve this problem.
>
> Thanks!
>
> Seth
> @capedcoder
>
>
>
> --
> FW/1 on RIAForge: http://fw1.riaforge.org/
>
> FW/1 on github: http://github.com/seancorfield/fw1
>
> FW/1 on Google Groups: http://groups.google.com/group/framework-one

 - Nathan Dintenfass

On Mon, Apr 9, 2012 at 6:27 PM, @CapedCoder  wrote:
> Hi All,
>
> I'm looking for some feedback on implementing security in my application.
>
> What I was thinking of doing is adding an annotation of permissions="myrole"
> to those methods I want to secure in my controllers.  I would then extend
> each of my controllers that have "secure" methods with a base controller in
> which the before() method would inspect the metadata for the method in the
> cfc that I am calling e.g. startManageArticles.  If the particular method
> has a "permissions" property it would compare that property against their
> array of permissions and redirect them to another page if it does not
> exist.  The only caveat I have found is that if I want my target controller
> to have a before() function, I have to call super.before(rc) in order to
> enforce the security.  I have tested this and it does work, but I'm not sure
> if it is good practice.
>
> I'm interested in hearing how other folks have addressed this common problem
> and whether or not this may be a good way to solve this problem.
>
> Thanks!
>
> Seth
> @capedcoder
>
>
>
> --
> FW/1 on RIAForge: http://fw1.riaforge.org/
>
> FW/1 on github: http://github.com/seancorfield/fw1
>
> FW/1 on Google Groups: http://groups.google.com/group/framework-one

 - Nathan Dintenfass

Seth Johnson

unread,
Apr 10, 2012, 12:09:30 AM4/10/12
to framew...@googlegroups.com
Good points James.  I like my controllers like my spaghetti, thin (no pun intended).

--

Nando

unread,
Apr 10, 2012, 8:12:13 AM4/10/12
to framew...@googlegroups.com
My thought is that if you are going to relate security to controller methods, then you'd be much better off implementing a "key" based security model over a "role" based security model. Not sure how you have that aspect set up, but I thought I'd mention it because security is often associated with roles.

In a key-based model, users are assigned all the keys they need to allow access to restricted functionality, just like an employee would be given a set of keys to open particular doors in a building that they need access to, but no more. Then your system will be flexible enough to allow any user access to any functionality, or restrict any user from any functionality. I set these keys as a struct under session.permissionKey (for instance session.permissionKey.deleteUser) when the user logs in. Then in your base controller's before method, you can do whatever you like. If your security keys are named the same as your controller methods, then you wouldn't need to set a permission attribute on the controller method. In fact, you'd have access to that within FW/1's machinery as getItem() I believe (check the docs), so no need to inspect the metadata either. Just a simple 

if( not structkeyexists(session.permissionKey, getItem() ) { 
   variables.fw.redirect('main.restrictedArea')
}

would do. If you only wanted to restrict certain methods but not others, I'd simply put the redirect at the top of each controller method.

Keys can easily be added whenever you need them.

If you're using a role based model, you may potentially run into difficulty. You never know what the system owners / users are going to ask for in terms of permissions. When Sally needs to be able to delete users, even tho' she should not have an "admin" role, you're going to have to tell them "Sorry, but that's not possible". "Why not?" "Well, because Sally isn't an admin user and only admin users can delete other users". "Well then let's make her an admin!" "Ummm, well, that's not really a good idea ... " "Why not?" "Ummm, well, ummm, ok, I'll make her an admin user" - and then Sally has access to other functionality that she shouldn't have access to.

Yes, a key-based security method implies more settings per user than a role-based system, but to my mind, the upside of flexibility is worth it.
--
Nando Breiter

Aria Media
via Rompada 40
6987 Caslano
Switzerland


Seth Johnson

unread,
Apr 10, 2012, 8:58:34 AM4/10/12
to framew...@googlegroups.com
Yes, this make a lot of sense and is very similar to how I have been doing it.  Users belong to groups, groups have keys, but users can also have keys assigned to them that are not within their group (just in case you need to blur the lines between groups or give a user a temporary key.  When a user logs in I gather all of their group keys, and any of their individual keys into one array.  What i was trying to get away from was having a bunch of conditional logic in my controllers, because a user may have viewUsers key but not have addUser key and that would require putting that conditional logic into each controller.  Using the method I propose you may still have conditional logic in case you had a userForm() method and wanted to allow certain users to addUsers and others to editUsers, but a great deal could be abstracted out to the base controller.  I may even implement a list of permissions and just make sure the user has at least one to access the method e.g. permissions="addusers,editUsers" then handle the update or insert conditionally.

Seth

Simon Bingham

unread,
Apr 11, 2012, 6:50:19 AM4/11/12
to framew...@googlegroups.com

Seth Johnson

unread,
Apr 12, 2012, 12:37:52 AM4/12/12
to framew...@googlegroups.com

Thanks for the post Simon.  I haven't done much with subsystems, maybe its time to start looking deeper into them.


--

Jim Priest

unread,
Aug 2, 2012, 8:18:39 AM8/2/12
to framew...@googlegroups.com
Seth,

Was curious how you security model turned out and what you ended up going with...

I'm facing this same challenge - I have an admin area that is locked down (subsystem) and within that I need to further limit access for certain actions and areas.

Thanks,
Jim

Seth Johnson

unread,
Aug 2, 2012, 11:14:11 PM8/2/12
to framew...@googlegroups.com
I ended up using a base controller and extending that controller with all of my controllers that I needed to secure.  On each of the methods that I needed to secure I added an additional permission attribute, and then I use the metadata to determine if the logged in user has the required permission.  Please see below:

/* secured cfc */
component extends="base"  {
public any function init( fw ) {
variables.fw = fw;
return this;
}
public void function before( rc )  {
rc.section = 'chapters';
super.before(rc);
}
public function startDefault(any rc)
{
rc.getChapters = application.beanFactory.getBean('chapterService').getActiveChapters();
}
public function startManage(any rc) permissions="manageChapters"
{
rc.getChapters = application.beanFactory.getBean('chapterService').getChapters();
}
}

/* base.cfc */
component {
public any function init( fw ) {
variables.fw = fw;
return this;
}
function before(rc)
{
var permissions = '';
var mymethod = 'start' & listLast(rc.action,'.');
var functionMd = getMetadata(this)['functions'];
for (i=1;i lte arrayLen(functionMd);i++)
{
if (functionMd[i]['name'] eq mymethod)
{
if (structKeyExists(functionMd[i],'permissions'))
{
permissions = functionMd[i]['permissions'];
break;
}
}
}
if (len(permissions) and !arrayFindNoCase(session.user.rights,permissions))
{
rc.message = 'b_Please login to access this area.';
variables.fw.redirect('security','message');
}
}
}

--
Reply all
Reply to author
Forward
0 new messages