Download DOWNLOAD
Forums FORUMS
Blogs BLOGS
Forge FORGE
Help HELP
Marketplace MARKETPLACE
DotNetNuke Home
You are here >   Community > Blogs
Register  |  Login

DNN Blog

Aug 1

Posted by: Vicenç Masanas
8/1/2006 9:05 AM  RssIcon

There's a "old" feature in DNN that allows module developers to create their own custom permissions for the modules they are creating. This will allow you to create a module and specify more granular permissions than the default VIEW / EDIT options DotNetNuke provides by default.

Yet a very powerfull feature I've seen this option not being much used. Actually very few module use that.
Why? I think the reason is because of a lack of documentation and examples from DNN core modules itself (an exceptional exception is the UDT module, from which I based some of this code). So I thought it would be good idea to provide some explanation on this and a piece of sample code for everybody to use.

What do we want
The overall goal of this exercise is to create some custom permissions for a module so it can have other options than the VIEW / EDIT default permissions. For example, decide which roles will be able to edit a specific item in the module.
The new permissions for the module will appear *automatically* on the permission grid in the module settings page without any extra step on your (the developer) part.

Structure
DotNetNuke provides two tables that support this feature. First there is the Permission table where all permissions are defined

and then we have the ModulePermission table where permission for each module are stored.

Note that this table contains not just module related permissions but all permission types (including folder and tabs). If at any given time DNN supports more granular permissions for these objects you will see them defined here.

On the Modules side note that the default permissions are defined with a code of "SYSTEM_MODULE_DEFINITION".
So the first thing to do when creating custom permissions is decide a unique code for your module. I suggest you use something similar to "MODULE_YOURMODULENAME".
ModuleDefId is a reference to the module that "owns" the permissions and PermissionKey, PermissionName define every permission you want to add.

Setup
A small problem with the current solution is that DNN does not provide any automated way to install new permission definitions when a module is installed. I'm sure we will solve this in a future version.

So we'll have to create some code to handle this, and the best way of doing it is by implementing the core IUpgrade interface. This interface defines a method that will be called everytime a new version of the module is installed, even the first version. So just add this piece of code to your controller class to handle the setup of module permissions:

  162         public string UpgradeModule(string Version)

  163         {

  164             if (Version == "01.00.00")

  165             {

  166                 // Install module permissions

  167                 InitModulePermissions();

  168             }

  169             return Version;

  170         }

  171 

  172         private void InitModulePermissions()

  173         {

  174             PermissionController permCtl = new PermissionController();

  175             ArrayList arr = permCtl.GetPermissionByCodeAndKey(ModuleSecurity.PERMISSIONCODE, "");

  176 

  177             DesktopModuleController desktopMod = new DesktopModuleController();

  178             DesktopModuleInfo desktopInfo = desktopMod.GetDesktopModuleByModuleName("MyModule");

  179             ModuleDefinitionController modDef = new ModuleDefinitionController();

  180             ModuleDefinitionInfo modDefInfo = modDef.GetModuleDefinitionByName(desktopInfo.DesktopModuleID, "MyModule");

  181 

  182             try

  183             {

  184                 PermissionInfo pi = new PermissionInfo();

  185                 pi.ModuleDefID = modDefInfo.ModuleDefID;

  186                 pi.PermissionCode = ModuleSecurity.PERMISSIONCODE;

  187                 pi.PermissionKey = ModuleSecurity.PERMISSION1;

  188                 pi.PermissionName = "A custom permission";

  189                 permCtl.AddPermission(pi);

  190             }

  191             catch

  192             {

  193             }

  194             try

  195             {

  196                 PermissionInfo pi = new PermissionInfo();

  197                 pi.ModuleDefID = modDefInfo.ModuleDefID;

  198                 pi.PermissionCode = ModuleSecurity.PERMISSIONCODE;

  199                 pi.PermissionKey = ModuleSecurity.PERMISSION2;

  200                 pi.PermissionName = "Another custom permission";

  201                 permCtl.AddPermission(pi);

  202             }

  203             catch

  204             {

  205             }

  206         }

Note that this code references a class named ModuleSecurity, more on this in a moment.

At this point, when you enter the module settings page for any module of this kind you will see the custom permissions on the permission grid.

and this is how the permission table data should look now.

Use
At this point we have all the infrastructe ready to start using these permissions on our custom module.
Here is a sample class the encapsulates then common needs.
- it defines the permissions definition constants (used in all access to the data)

   23         // Constants

   24         public const string PERMISSION1 = "PERMISSION1";

   25         public const string PERMISSION2 = "PERMISSION2";

   26         public const string PERMISSIONCODE = "MODULE_MYMODULE";


- the interesting part in is the contructor, where you define a varible / property pair to define all the permissions in a more easy way.

 

   43         public ModuleSecurity(ModuleInfo modInfo)

   44         {

   45             ModulePermissionCollection permCollection;

   46             permCollection = modInfo.ModulePermissions;

   47 

   48             ModulePermissionController permCtl = new ModulePermissionController();

   49 

   50             _permission1 = ModulePermissionController.HasModulePermission(permCollection, PERMISSION1);

   51             _permission2 = ModulePermissionController.HasModulePermission(permCollection, PERMISSION2);

   52         }

 

- and finally define a couple properties to wrap these permissions:

 

   56         public bool CanDoThis

   57         {

   58             get { return _permission1; }

   59         }

   60         public bool CanDoThat

   61         {

   62             get { return _permission2; }

   63         }

Now you can use that class on your module's code and do something like that:

    1 ModuleSecurity ms = new ModuleSecurity(this.ModuleConfiguration);

    2 

    3 if (ms.CanDoThis)

    4 {

    5  // do it

    6  ...

    7 }

Conclusion
You can see that without much effort you can provide a much richer configuration interface to your module configuration using builtin DNN capabilities, and take advantage of the gread security features the framework has right out of the box.

Tags:
Categories:

31 comment(s) so far...


Re: Custom Module Permissions. Enhance your modules!

Hi, thank you for point out this!
But how do you easily localize those permissions names?

thanks

By doop on   8/1/2006 9:58 AM

Re: Custom Module Permissions. Enhance your modules!

I knew I forgot something ... :)
To localize the permission headers on the grid you have to create a SharedResources.resx file on your module App_LocalResources folder and add entries using the key naming:
.Permission

Where permission name is the value stored in the PermissionName column in the db. So in our example they would be:

A custom permission.Permission
Another custom permission.Permission

By vmasanas on   8/1/2006 10:10 AM

Re: Custom Module Permissions. Enhance your modules!

I've used this maybe a year ago, it's a great thing and can be elevated to much higher ground than it is now.

What I've missed then (to complete it) was the ability to define custom permissions in .dnn file and install them when the module is installed.

Also back then, I made a custom CodeSmith template to provide me with Intellisense support for permission checking through the use of generated enumerations and functions defined in a custom xml file(e.g. If (HasPermission(Permission.Moderate) Then...).

It's really a great thing, too bad that it isn't used much.

regards,
Vladan Strigo

By vladan on   8/1/2006 12:27 PM

Re: Custom Module Permissions. Enhance your modules!

This is a great article, Vicenç. I knew of the possibility but never had or took the time to figure it out. Thanks a lot for showing how to use a great feature like this.

Stefan

By superska on   8/1/2006 12:27 PM

Re: Custom Module Permissions. Enhance your modules!

Thanks Vicenç - So just to confirm - this will be put in at Module Level? Eg. in my Events module I have a Events Admin permission (I currently allow users to select 1 or more roles from a list in Module Setting - this would replace that?)

One thing - how does Uninstall work - will it erase the Module Permissions from that table? Because the code is in Upgrade() - would you be able to reinstall it?

Good work...
Thanks
Rodney
http://www.smart-thinker.com

By rodneyjoyce on   8/1/2006 5:10 PM

Re: Custom Module Permissions. Enhance your modules!

Rodney,
yes, this should replace your custom code to handle special access for users. That's right.

On the uninstall part, there's currently no automated way of installing / uninstalling these permissions. But as I've already mentioned this is our roadmap for a future version. Regarding reinstalls, if you take a closer look, you'll see the creation of permissions is in "try catch" block. So even if the module is given the same ModuleDefId on a reinstall this code will not fail and just use the previous definitions.

By vmasanas on   8/1/2006 5:14 PM

Re: Custom Module Permissions. Enhance your modules!

Vincenc, I really think that this feature of DNN would be used more if the framework fully supported it (install / uninstall, etc). I would have used custom permissions for the TestCase module I am working on, but decided against if because did not want user having to manually enter data into DNN tables to get it to work properly.

This is a greate tutorial on how to implement this, and I will keep it handy for future references. I will definately look at using this for any internal modules I write.

By smehaffie on   8/2/2006 7:25 AM

Re: Custom Module Permissions. Enhance your modules!

I see you all agree on one thing I was missing... install/uninstall option.

It would be really great when the framework would support it. WIthout it, you can work... but to be honest, it's a pain :)

regards,
Vladan Strigo

By vladan on   8/2/2006 10:33 PM

Re: Custom Module Permissions. Enhance your modules!

How to allow an admin (currently logged in user) to check custom permissions for a selected User?

I will have to explain the intent.

For an application I created a portal wide security configuration module that would allow application level roles to DNN roles (1 application role can be mapped to 1, 2 or more DNN roles). This required to hard code the names and values for the custom permissions. Your solution is good in that it allows simple DB change to show new permission. Of course you still have to hard code permission names in your code to utilize that.

I have a question. This works fine if the current user's roles is checked against custom permissions, but I have the case when certain pages can be seen by both a user and an admin (it is similar to Create User page where admin or user himself can enter the same information when registering/editing. I understand that admin pages are different from users when registering/editing so there is no conflict. ) In my case the page is the same for both user and admin. If we imagine that the admin and the user end up at the same Register/Edit page I would like the admin to add let's say a comment in addition to other fields that the regular user sees. There could be yet another permission that would allow yet more functions. In that case the admin is acting on behalf of the user.

However what I want to achieve as an admin is to check custom permissions for that user while I am on that page and if the user has let's say a "Power user" custom permission I would as admin see extra fields.

I implemented separate methods IsCurrentUserInRoles (for selected user with a known UserID) and IsUserInRoles (which uses DNN built in security checking based on the currently selected user.

So my question is how to use this method to achieve this.

Thanks,
Rad

By raca on   8/5/2006 12:25 PM

Re: Custom Module Permissions. Enhance your modules!

Rad,
I'm not sure I completelly understand what you want/need.
I think what you need is what DNN offers out of the box using my explanation above:
- you create "module permissions" or "module roles", call it as you want
- then map, give permissions, assing, call it as you want, to existing DNN roles

Then to know if a given users has a given module permission or module role, you only have to know what DNN roles the user belongs to and what permissions have these roles assigned on any given module.

Vicenç

By vmasanas on   8/5/2006 12:29 PM

Re: Custom Module Permissions. Enhance your modules!

Great article. Thanks. was very usefull.

I wonder how could I manage permissions for a page (a tab) if I want have a kind of moderated page kind. I mean, how I can code the logic a page that need previously be aproved before can be viewed for a special user.

I think can be easy for a new module created by myself, but how about the pages?

Thanks

By Greibach on   8/9/2006 2:08 PM

Re: Custom Module Permissions. Enhance your modules!

Vicenç,
I understand how to use this feature for the currently logged in user. What I want is as an admin to be able to do some actions based on a selected user.

Let's say I create a ”SchoolMember List” page that is based on a combination of Users table (DNN) and an additional SchoolMember table (custom table). Some SchoolMember-s are students, some are teachers, mentors etc. They all might have appropriate table linked to SchoolMember table.

I want when the admin select a SchoolMember from ”SchoolMember List” page, to do something on a separate “Maintenance” page that depends on the permissions of THAT user and NOT on the admin – who is currently logged in user (or other power user) permissions. This Maintenance page can also be used by any SchoolMember to do some updates and it that case your suggestion works, but I need the admin user's operation to depend on the selected SchoolMember.
I hope this clarifies my intention. This might not be built in DNN, but my question is how to extend it.
This little fragment explains built-in DNN function inside PortalSecurity class.
The problem lies in UserController.GetCurrentUserInfo call. It will only retrive current user’s info and his roles.
I need something along the lines of UserController.GetSelectedUserInfo(userid) inside a new function:
Public Shared Function IsInRoles(ByVal userid as integer, ByVal roles As String) As Boolean


DNN version.
Public Shared Function IsInRoles(ByVal roles As String) As Boolean
Dim objRoles As New Microsoft.ScalableHosting.Security.Roles

Dim objUserInfo As UserInfo = UserController.GetCurrentUserInfo

Thanks,
Rad

By raca on   8/11/2006 7:24 AM

Re: Custom Module Permissions. Enhance your modules!

Nice feature, thank your for showing us how to use it. I've added my own permission for a module I'm working on and it's working great. But I would like to default my custom permission to be either like the "View" permission where it can in herit from the page "View" permissions or default to granting the "All Users" role my permission. In other words, by default I want everyone to have my permission, as it stands no one does until it is granted. What would be the best way to accomplish this?

Thanks,
Dave

By ddaiker on   8/12/2006 8:20 AM
Gravatar

Re: Custom Module Permissions. Enhance your modules!

Is there any updated documentation on this? This is darn near 3 years old and still seems to be the best documentation of integration with permissions that I was able to find with Bing.

By David OLeary on   7/26/2009 5:41 AM
Gravatar

Re: Custom Module Permissions. Enhance your modules!

Just found this article, www.codeproject.com/KB/aspnet/dnn_custom_permissions.aspx

It appears to be a much more up to date explanation of integrating with the new ModulePermissions architecture.

By David OLeary on   7/26/2009 5:51 AM

Re: Custom Module Permissions. Enhance your modules!

Rad,
Ok, I see what you mean now. And sorry, but no, this is not possible out of the box.
You will have to code you own "IsInRoles(UserId,Roles)". Though, I've seen this question asked a few times in forums so maybe it would be a good idea to provide something similar on the dnn framework.

Vicenç

By vmasanas on   8/11/2006 7:28 AM

Re: Custom Module Permissions. Enhance your modules!

You are right, there's no uninstall interface or procedure to remove these permissions. This is something we are aware of and will try to solve in a future release.
Thanks.

By vmasanas on   4/14/2007 7:32 AM

Re: Custom Module Permissions. Enhance your modules!

rodney,
sorry for the delay on the answers but I didn't get a notice about it. Anyway...

As you said permissions are tied to moduleDefinitions, so yes, you'll have to define them for each one.
Notice that when you put a module on a page, what you actually do is put an instance of a given moduleDef so it makes sense to work this way.

Performace: I think permissions are now (DNN 4.4) much more performant. Charles did a very good job on improving that part.

Regarding accessing the ModuleDefId on the sql script: this will not work, since module registration is the last step in the module installation, so this value is not yet available when the script is run.

Rodney take a look at my other blog post regarding module installation to understand your problems with IUpgradeable firing more than you expected.

Vicenç

By vmasanas on   2/8/2007 11:19 AM

Re: Custom Module Permissions. Enhance your modules!

HBenton,
I'm sorry but this code is from a custom module I cannot post. But as I said in the UDT module you will find some pieces that work pretty much the same as my example.
Vicenç

By vmasanas on   2/8/2007 11:21 AM

Re: Custom Module Permissions. Enhance your modules!

You have two options here:
- use the "View" permission for your needs
- add code to the module so it adds the permission to "All Users" when it's first added to the page (you'll need some sort of module setting to detect this case)

By vmasanas on   8/17/2006 8:00 AM

Re: Custom Module Permissions. Enhance your modules!

HBenton,
you can take a look at the UDT module for a similar use of the custom module permissions. They don't use the same exact pattern I used on my example but it's quite similar.
Vicenç

By vmasanas on   9/5/2006 3:24 PM

Re: Custom Module Permissions. Enhance your modules!

HBenton,
you should take a look at the file Security\ModuleSecurity.vb . This is not exactly the same as I pointed here but can give you a couple ideas. Also on the Settings.ascx.vb, they setup the permissions on the tables using a different approach than mine.
Vicenç

By vmasanas on   9/6/2006 9:20 PM

Re: Custom Module Permissions. Enhance your modules!

Using the code above what NAMESPACE would I find this in "ModuleSecurity."?

By KevinDonahoe on   3/13/2007 5:17 AM

Re: Custom Module Permissions. Enhance your modules!

Hi Vicenç,
I am now using this in my Events module and have come across a design problem possibly. Basically I wanted to select a Role called Event Admin (EA). EA can always do anything a user can with Events. So I added the new permission, but I assume if I make the ModuleDefIF -1 like View and Edit then it will appear on ALL modules on the portal? So I have to tie it to one definition.

The problem here is that my modules are complex, so I have different views. ie. I display a list of events (so EA might have more options) and then you click on one and it goes to the Detail definition. From what I can see I am going to have to insert the same permission at for the module def and for and def that uses it?

This makes configuration quite a pain - instead of being able to select a role once and saying "all peeps in this role are admin", I know have to set it up at module def. level each time.

Did I explain this clearly? Is there an easier way than inserting this perm for every mod. def. in a module?

Thanks!
Rodney
www.smart-thinker.com


By rodneyjoyce on   2/8/2007 11:08 AM

Re: Custom Module Permissions. Enhance your modules!

One more thing, I check HasAdminPerms quite often; should the module perms not be cached? It does 2 DB hits each time they are checked (and I check them often in all my modules)

ModuleController moduleController = new ModuleController();
ModuleInfo moduleInfo = moduleController.GetModule(moduleID, tabID);
if (moduleInfo != null)
{
hasAdminPermission = ModulePermissionController.HasModulePermission(moduleInfo.ModulePermissions, EventAdminCustomPermission);
}

By rodneyjoyce on   2/8/2007 11:08 AM

Re: Custom Module Permissions. Enhance your modules!

Hi again

I have been trying to implement this so that the custom perms install in a new version of my Events module.

Firstly, I tried to insert the perms using SQL -
/* Add Custom Permissions for each Module Defintion */
DECLARE @ModDefID as INT
-- This FriendlyName cannot be changed
SET @ModDefID = (SELECT ModuleDefID FROM {objectQualifier}ModuleDefinitions WHERE FriendlyName = 'Smart-Thinker - Event')
INSERT INTO {objectQualifier}Permission(PermissionCode, ModuleDefID, PermissionKey, PermissionName) VALUES ('SMART_THINKER_EVENTS', @ModDefID, 'EVENTADMIN', 'Event Admin')
GO

which looks fine but does not work. I THINK it is because the module definititons have not been registered before the SQL sctipts, hence the ModDefID is NULL. I presume that this would work on an upgrade but it is useless if it cannot work on a new install.

So then I looked at your code in IUpgradeable. I can see 1 potential problems on Upgrades:

DesktopModuleInfo desktopInfo = desktopMod.GetDesktopModuleByModuleName("MyModule");

This name is changeable, so while it will work for all new installs IF they changed the FN of the module (which more and more of my customers seem to be doing purely because the default skins render the module drop downlist so narrowly!) then upgrades would not work.

I am still trying to get it to work but I'll let you know my findings - hopefully this helps someone (spent literally the whole day on this so far ;)

Thanks
Rodney
www.smart-thinker.com

By rodneyjoyce on   2/8/2007 11:09 AM

Re: Custom Module Permissions. Enhance your modules!

One more post on this matter. I reinstalled the SAME version of the module and the upgrade code fires again. This resulted in duplicate entries in the Perms table and the Settings page bombed. some code should be done to check that they do not exist first (until the core installer is clever enough to realize that the same version is being installed).

By rodneyjoyce on   2/8/2007 11:08 AM

Re: Custom Module Permissions. Enhance your modules!

Forgive my lack of knowledge, but where would I find the UDT module?

By HBenton on   9/6/2006 9:16 PM

Re: Custom Module Permissions. Enhance your modules!

I figured out what you meant by the UDT (User Defined Table) module, however is there any particular area that I should look specifically at?

Thank you in advance for your help!

By HBenton on   9/6/2006 9:16 PM

Re: Custom Module Permissions. Enhance your modules!

Do you have a downloadable example of the code you used for this tutorial?

I believe I understand what the tutorial is showing, however, I would like to see the code in a real example ... I hope that makes sense :)

HBenton

By HBenton on   9/5/2006 3:20 PM

Re: Custom Module Permissions. Enhance your modules!

What about uninstall ? :-) I desesperately looking an uninstall interface somewhere ?

By lolocmwa on   4/14/2007 7:31 AM

Networks

Follow DNNCorp on Twitter Follow DNN Community on Twitter

LinkedIn

Follow us on Twitter @DNNCorp & @DNN or join the DotNetNuke Community on LinkedIn

Sponsors

DotNetNuke®, DNN®, and the DotNetNuke logo are trademarks of DotNetNuke Corporation

Hosted by MaximumASP