Tuesday, September 05, 2006

Today I received an update to a suggestion I made to Microsoft on April 8, 2005.  http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=102180  That was before Beta 2 of Whidbey if memory serves me right.  My suggestion was to add features to the Membership API that would allow for a user to be renamed.  There are many scenerios where we choose to use the full Email address of a user as their username instead of having a seperate username.  This works great until the user changes their Email address.  (Another reason to have a permanent address that is not affiliated with your ISP)  I need to be able to allow users to update their Email address and thus their username/userid. 

Apparently my suggestion has been considered for Orcas, but isn't going to make it.  Still, I thought it was good that it was at least considered.

In the meantime, I have found that I can rename a user by directly updating the membership database.  Microsoft cautions against this when using multiple stores for Membership, Roles, and Profile data because user + application is the identity that is shared across disparate stores.  It is my opinion that they should have used a unique identifier instead.  The MembershipUser supports such an identity already.  Similiarly I wish Windows authenticated users and forms authenticated users shared a common data type for their identities.  I believe Microsoft would say that indeed they do and this is the string type that the username or User.Identity.Name.  For my purposes I created a database table to map a GUID to Windows identities so that I could normalize all of my UserId's to be unique and meaningless.  A Email address as a username carries meaning.  That makes a bad primary data key in many scenarios because of the lack of good support for renaming.  Keys should never need renaming.  Even a Windows UserId can change when its based on a persons name and their legal name changes.

What do you all think?

 

9/5/2006 9:35:09 PM (Mountain Daylight Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Wednesday, November 23, 2005

It seems like forever ago that I started recommending Fredrik Normen's Permission Manager.  Recently I was tasked to find a way to restrict nodes in a SiteMap based on Permission.  Today I completed that task and thought I would share it with the world.  First of all, I appoligize for writing the code in VB.NET (employers standard), but you can all compile it and reference it from C# so get over it.

What I did to create the PermissionXmlSiteMapProvider was to inherit directly from XmlSiteMapProvider and then extend 2 methods.  First of all I extended the Initialize method so that I could verify that it was configured properly.  Since it is dependent on the presence of Permission Manager and it properly working I added a simple check to verify that it has a provider.

The second method to override for the addtion of Permission to a SiteNode was IsAccessibleToUser.  Thankfully the siteNode can have extra attributes on it without complaint.  I used that to check for the permission attribute.  If it is there then a call to Permission Manager is done for the named permission and the currently logged in user.

After configuring my applications to use my new Provider I restrict access to nodes as easy as this:

<siteMapNode url="Edit.aspx" title="Edit" permission="Modify" />

Since I built on top of the XmlSiteMapProvider I also get the ability to do Roles restriction and a combination of Roles and permission:

<siteMapNode url="Delete.aspx" title="Delete" Roles="Admins, Editors" permission="Delete" />

It is important to note a few things that I ran into while working on this solution.  You must enable Security Trimming.  If you will restrict based on Roles you also must enable RoleManager.  Restricting via Roles is a little quirky as described in the MSDN Site Map Providers document.  Specifically review the Security Trimming section.

Here is the siteMap section of Web.config that implements the PermssionXmlSiteMapProvider:

<siteMap enabled="true" defaultProvider="PersmissionXmlSiteMapProvider">
  <
providers>
    <
add name="PersmissionXmlSiteMapProvider
           
type="IDCL.Web.Security.PersmissionXmlSiteMapProvider, IDCL.Web"
           
description="Permission xml site map provider"
          
securityTrimmingEnabled="true"
          
siteMapFile="Web.sitemap"/>
  providers>
siteMap>

Obviously you also need to have Permission Manager installed and configured or this will not work.

Here is the code for the provider:

Imports System
Imports System.Web
Imports System.Configuration.Provider
Imports System.Web.Configuration
Imports Nsquared2.Security

Public Class PersmissionXmlSiteMapProvider
Inherits XmlSiteMapProvider

Public Overrides Sub Initialize(ByVal name As String, ByVal config As System.Collections.Specialized.NameValueCollection)

' Verify that config isn't null
If config Is Nothing Then
  Throw New ArgumentNullException("config")
End If

' Verify that Permission Manager is configured
If PermissionManager.Provider Is Nothing Then
  Throw New ProviderException("Permission Manager default provider missing.")
End If

' Add a default "description" attribute to config if the
' attribute doesn't exist or is empty
If String.IsNullOrEmpty(config("description")) Then
  config.Remove("description")
  config.Add(
"description", "PermissionXmlSiteMap provider")
End If

' Call the base class's Initialize method
MyBase.Initialize(name, config)
End Sub

Public Overrides Function IsAccessibleToUser(ByVal context As System.Web.HttpContext, ByVal node As System.Web.SiteMapNode) As Boolean

  Dim authorized As Boolean = MyBase.IsAccessibleToUser(context, node)

  'Pull the permission out of the sitemap node as an attribute
  Dim Permission As String = node.Item("permission")
  If Not Permission Is Nothing And authorized Then
    If context.User.Identity.IsAuthenticated Then
      ' Only check permission for known users
      Return PermissionManager.HasUserPermission(context.User.Identity.Name, Permission)
    Else
      ' The presence of a permission requires a known user
      Return False
    End If
  End If

Return authorized

End Function
End
Class

The PermissionSiteMapProvider.zip file with this article includes the Provider solution and a sample web.config

11/23/2005 4:27:33 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 19, 2005

For those of you who are following the back ported Membership API I have some news.  Tonight I had opportunity to visit with Scott Guthrie and I asked him when we might see the download return.  He indicated that it was likely not to return.  Currently DotNetNuke and Community Server are both licensed to use it.  Others can request it and will likely be granted license, but the issues around supporting it are apparently causing Microsoft to hold back on releasing it openly.  For those wanting to check it out you probably should plan on following the steps I outlined when it first appeared.  I will leave the latest changes in implementation to you for now.  Those who really want it will need to find a way to request it from the ASP.NET team.

Scott Guthrie, here is a thought.  Perhaps you could give it to a 3rd party like myself or someone else who could maintain it in an open source model.  That would free Microsoft from supporting it and still allow the community to begin writing against it to prepare for .NET 2.0 and gain its advantages today.  I would be happy to rebuild it under a new namespace to remove Microsoft from responsibility for support and updates.

A couple other news items from Scott.  Sharepoint 2006 or whatever the next version is called will support forms authentication for Internet sites.  He has updated his VirtualPathProvider sample code for Beta 2 of VS 2005.  See the download for the March 20, 2005 talk from VS Connections in Orlando.

4/19/2005 11:30:29 PM (Mountain Daylight Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Wednesday, February 09, 2005

Permission Manager has been updated for Beta 2 of VS 2005.  The more exciting part is the addition of Authorization Manager.  This is similar to the AzMan from Microsoft in purpose.  The best part about Fredrik's version however is that it is true .NET and does not require any install (think standard .NET XCopy) or COM+ registration like AzMan.  For more info head on over to the run down on Fredrik's blog.

2/9/2005 10:32:38 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, November 26, 2004

In my previous Microsoft.ScalableHosting post I described with some excitement the .NET 1.x Membership API found hidden inside of DotNetNuke 3.0.  My excitement is mostly about using the API outside of DNN.  There is also excitement about the possibility of DNN supporting alternate authentication stores through the provider model and the improved API.  Windows authentication is something missing from previous DNN that may work well now.  I have not yet tried it.

 

2 days ago a document describing Membership usage inside of DNN was posted.  The reading of that document prompted several thoughts which I will share here.

 

Why use Microsoft’s Membership API? 

One of the important things the API does for us is standardize how authentication is handled in ASP.NET.  With everyone cooking up their own solutions we constantly are learning a different authentication methodology and system with every application.  With standardization of the API we can now use front end tools like the Login controls in ASP.NET 2.0.  As long as developers stick with the base API’s, controls can be written against them and have high levels of assurance that they will work consistently.

 

Second, an equally important feature of Membership is the underlying provider model for implementation.  With a provider back-end developers are able to completely customize their data storage and data access as it related to Membership.  This design pattern also allows every application that uses the Membership API to share user accounts and roles when so desired.  How many times have we heard the complaints that ASP.NET Forums doesn’t use the same authentication system as DNN, Rainbow and IBS.  As these systems are updated to support the Membership API the only thing required to share authentication will be a configuration line in the web.config to point them all at the same provider.

 

DNN 3.0 Membership description falls short!

The reason for this whole post is to share my belief that DNN 3.0 falls short in its implementation of Membership or at least the description of such.  Throughout the DotNetNuke Membership document I was disturbed by the logic I discovered.  In the section DotNetNuke & Whidbey (Page 1) Shaun Walker says that DNN must avoid creating its own provider to simplify future migration.  This is absolutely backward and representative of other architecture decisions that continue to pain DNN.  DNN already has a robust solution for membership data.  Apparently there are business rule dependencies at the data level in some places (Page 7, UserRoles).  DNN is classic textbook example of an application that should create its own membership providers for use with the API.  By doing so other applications could share DNN’s user base easily and DNN would not be forced to make as many core changes.

 

On one hand I am glad to see that Satellite tables have been created in DNN to separate Membership data for DNN specific user/roles data.  On the other hand, the integration issues should have nothing to do with the underlying data storage and instead be addressed in the DNN API’s.  With a custom DNN Membership system both the Microsoft Membership API and the DNN specifics could easily be combined.  This would allow DNN to use any Membership provider while still supporting all of the DNN specifics and managing synchronization issues.  Page 9 CBO (Custom Business Objects) is exactly the right approach.  I believe the issues are being addressed, but the failure to see things from a Domain (objects, services) perspective really bothers me.  DNN thinking still tightly couples Data structures and the API’s and the 2 should be considered separately. 

 

Sharing users between portals is now a simple matter of sharing the ApplicationName that the Membership provider uses.  To make users unique all that is needed is to use unique ApplicationName’s.  The scenarios presented in Deployment Scenarios on Pages 1-2, Data on Page 3 and Multiple Portals on Page 10 do not make much sense.  By standardizing on the API, any deployment should be supported as long as a provider is used that supports the desired scenario.  The provider is the implementation and it is the key to supporting different scenarios.  Thankfully MembershipProvider.ApplicationName can be changed on each request enabling support for multiple portals with or without shared authentication systems.  By using multiple providers it is even possible to use different authentication stores for each portal in a DNN multiple portal scenario.

 

In Development Tasks (Page 2) it is apparent to me that there is a significant misunderstanding of Membership that must be clarified.  It is true that the UI controls built on top of Membership have not been back ported.  But there is a clear separation of the API and the SQL DB & Provider.  The API and the Provider should not be confused.  They must be considered as independent components.  Sure they work together, but the API does not in any way dictate underlying provider or storage that is used.  See the sidebar on the Membership API architecture at the end of this post.

 

When I hit the Data section at the end of page 2 and beginning of page 3 hope was returned to me.  Separation of responsibility is acknowledged between DNN data and the Membership data.  This is absolutely critical in order to use providers that only give DNN access to the data through the API and not in the database.  This separation creates a new paradigm for some developers.  It requires business rules to be placed in code and not in stored procedures.  The code has full access to the data through the API, but the database has no access to it or knowledge of it unless developers violate the intended usage.  If you are used to putting rules in your database it’s time to quit it!  You are asking for trouble with Membership data if you do this.  Thankfully DNN has fully acknowledged this in the Membership area.  Now we all need to be building software with the principles of separation of responsibility from the foundation.

 

Custom Attributes on Page 4 shows more confusion about the API and Provider.  It leads me again to believe futher that a DNN provider and custom DNN system would be best.  The custom attributes of course would still have to be treated as DNN specific data, but that is acceptable and exists no matter how Membership is implemented.  (DNN developers, I am not suggesting you replace Micrsoft's Membership, merely that you wrap it to support your additonal features.)

 

As a final note I want to publicly state that even though I have been critical of DNN here I am mostly seeing a reflection of my own failures in software development.  Now I desire to improve my own practices and help others see the benefits of good architecture and patterns as well.  With DNN’s prolific exposure it deserves a careful critique so that its best practices are adopted and its worst avoided.  This critique in no way reflects my opinions of Shaun Walker or any DNN developers.  Shaun and I have met personally and I enjoyed my meeting with him.  I also have great respect for him and his work in the ASP.NET community through the DNN portal.  Some readers may also know that I work with Rainbow Portal.  I choose not to be a fanatic about software and this post is neither for nor against DNN.  Each person must choose the solution that is best for them.

 

Sidebar: UserName and RoleName are not updatable through the Membership API as indicated in the DNN document.  The SQL database that goes with the default SQLMembershipProvider does not prevent you from updating UserName or RoleName through your own tools.  All relationships within the database are done by unique id’s so changing names will not break anything.  If you desire to change these names you must simply take care to update your own systems that may reference them and also to ensure that you keep them unique per application.  (Application referring to the definition of application inside of the SQL Membership database.)  Perhaps Microsoft should expose UserId and RoleId through the API so that we can store those in our applications instead of storing username and rolename as the unique ID’s provided through the API currently. 

 

Let me suggest a Membership best practice here.  Windows authentication uniquely identifies users as DOMAIN\USERNAME.  When using the Membership API with forms authentication I suggest always using APPLICATIONNAME\USERNAME.  By doing that you will be able to uniquely reference Membership users throughout your systems and not have to worry as much about username conflicts that could occur otherwise.

 

Sidebar: A look at the Membership API architecture reveals a nice model that may fit many other areas well.  MembershipUser is a simple entity to work with.  Its functionality is limited a single are of responsibility.  It knows nothing about the data store it is persisted in or even if it is persisted.  It also knows nothing about the collections it may be contained in (Roles).  To interact with an underlying storage system the Membership API acts as a service layer between the MembershipUser entity and a persistence Provider.  The Provider layer allows for complete control of the Membership implementation as it interacts with a persistence store.  The store may be a database, flat files, memory stream, or anything a developer chooses to be the implementation of the fields and methods required by the Membership system.  Developers are given a standard API to program against without concern for the underlying database.  The database designers do not have to be concerned with the API or the Domain entities that may represent the data.

 

11/26/2004 3:07:17 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Monday, November 22, 2004

using Microsoft.ScalableHosting;  // What is this namespace all about?  Read on!

With the release of DotNetNuke 3.04 in public beta comes a very interesting and powerful assembly.  A close look in the MemberRole.dll reveals that it is a fully functional port of the ASP.NET 2.0 Membership API.  So far it also looks to be a complete port.  The API includes features not even found in ASP.NET 2.0 Beta 1 such as account lockout.  This assembly contains several classes in the Microsoft.ScalableHosting namespace.  Classes inside this assembly include:

ProviderBase
Profile, Membership and Roles specific configuration classes
Profile + SqlProfileProvider
AnonymousIdentificationModule (httpModule)
Membership + SqlMembershipProvider
MembershipUser
Roles + SqlRoleProvider
RoleManagerModule (httpModule)

There are many additional classes as well.  I extracted the necessary configuration in web.config and put together a simple application to test the API.  I had no problem creating users and adding them to roles.  The API and SQL Providers worked perfectly with both Forms and Windows authentication.

Note: when using Windows authentication and adding a user to a Role a MembershipUser record is added to the database.  I am now wondering how the aspnet_Users and aspnet_UsersInRoles tables will get cleaned up when a Windows account is deleted.  This is currently necessary to create the GUID for the Windows account that is added to the aspnet_UsersInRoles table.  ASP.NET team comment please!

The license information for this assembly can be found at: DNN3\controls\MemberRole\Member Roles (Conf) (1101204) FINAL.doc.  Looks like this is some kind of Beta release of the API.

The SQL database installation script is found at: DNN3\Providers\DataProviders\SqlDataProvider\InstallRolesProfileMembership.sql  You will need to do a global replace of {databaseOwner} in the file with dbo. or other appropriate ownership for your scenario.

To use the API's in your own application you will need to do a few simple things.

  1. Reference MemberRole.dll
  2. Create the SQL database (or write your own custom providers)
  3. Put the appropriate settings in web.config.  (sample web.config)

To create your own providers start a new class project, reference memberrole.dll, inherit the appropriate provider base class and override the abstract methods and properties (Microsoft.SecureHosting.ProfileProvider, Microsoft.SecureHosting.MembershipProvider, or Microsoft.SecureHosting.RoleProvider).  Then reference your new provider in the configuration.

You can of course leave out any configuration and providers details that you are not interested in using.  The RoleManagerModule must be added to the httpModules collection if you want to have the roles for a user added to the authentication cookie as is common practice in 1.x applications.

If you are interested in more details about the Provider Design Pattern I plan to post addtional information and providers at www.aspnetproviders.com.

Now that I have the MembershipUser and Roles I am planning to port PermissionManager to .NET 1.x as well.  Together with Membership the PermissionManager completes authentication and authorization package allowing us to abstract all aspects of security management out of applications.

How will you make use of Membership, Roles, and Profile for your current applications?

11/22/2004 10:45:06 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, November 19, 2004

My friend Fredrik Normen is at it again.  Permission Manager continues to improve.  Perhaps we should take it even further?

The latest enhancements give us the ability to specify permissions in the config file as well as other provider defined locations. 

 What does everyone think about putting this kind of configuration in an PermissionManager.config file or something like that as an option?  I imagine the web.config might like this: 

<permissionManager enabled="true" path="PermissionManager.config" />

As you can see all the remaining details might be found in an external config.  It seems with all the provider stuff the web.config is growing to be a very large file.  Of course we would want to still be able to use the Configuration API's as much as possible.

Thoughts on configuration and web.config usage?

For Permission Manager what about defining permissions in a custom attribute class and then having a reflection provider that harvests them from the assemblies during initialization.  My thinking is that we have a synchronization issue between the permissions defined in application and those defined in the provider store.  By using attributes and reflection the definitions in the code would always be in sync.  It would not be necessary to define the permissions in any external location.


Today we might define a Permission to secure a method like this:

public void foo () {
// Check Permission
if (!(PermissionManager.HasPermission(“Group“, "Permission", user))) {return false};
// Permission granted
// do stuff

For this to work we also must make sure that the “Group“ and “Permission“ exist in the permission definition store.  This requires us to create the definition prior to executing a .HasPermission().


With attributes we could perhaps do this instead:

 // Check Permission automatically for current user? and define permission declaratively
[Permission(Group="Name", Permission="Name", Description="Description")]
public void foo () {
// do stuff

Now with reflection we can harvest the necessary permission definitions right out of the assembly.  Any assembly that has a dependency on Permission Manager self describes the permissions it uses and checks attributes.  I still need to understand the details and possibilities around this, but it seems there must be a way to use attributes to define the permission and secure fields, methods, and classes.  The Conditional(”DEBUG”) attribute seems similar in concept.  Permission Manager defines a condition based on runtime security instead of compile time.  Those who have worked with attributes more please comment as to the feasibility here for both definition of permissions and runtime authorization checks.

11/19/2004 11:42:52 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, July 12, 2004

A few months back I was talking with some other developers on the v.Next project about how we could abstract security out of our code.  The desire was to have methods and code blocks that could be wrapped with security checks, but without hard coding user or role names.  The current IBuySpy and Rainbow Portal for example have code in them like this if (User.IsInRole("Editor")) {do stuff}.  That works fine for a simple application, but what happens when you want to allow Admins and Editors?  In today's model you end up modifying the code and re-compiling and deploying.  I have seen a lot of code that strings together a bunch of OR statements when additional Roles need to be supported for a given security check.  It can get very ugly.

The solution is to have the authorization and permissions abstracted from the application so that when Users and Roles change you can easily change the security inside the application without changing code.  Enter Permission Manager (PM).  PM is the coolest piece of code I have seen for Whidbey so far.  I really can't believe something this good is already available and Whidbey just hit Beta 1.  It could be that I was already talking about building something like this that makes it cool, but for me it is how nicely it fits the ASP.NET 2.0 experience.  The code looks like it is native to ASP.NET.  It seems to follow the style of Microsoft's built-in classes very nicely.  It plugs in beautifully to the provider model allowing you to use it with your own custom provider for managing the permission sets for an application.

PM works by allowing the developer to create an abstracted permission object that implements IAccessObject.  This is simple to implement with basic name and ID properties.  The object then is used with the PermissionManager to create named permissions.  The sample has a news object that is used to create various permissions.  These permissions are completely separate from Users and Roles until you map them together.  For example, within the news permission set we may want a print and copy permission.  Using the PermissionManager static methods we make simple calls like: PermissionManager.CreatePermission(news.SourceGroup, "Copy", "Copy a document"); to create the Copy Permission.  When we want to map a real Role to the Copy permission of the news object we simply execute a method like this: PermissionManager.SetPermissionForRole("Copypeople", news, "Copy");.  This maps the Role of Copypeople to the permission of Copy on the news object.  news really is just an object for grouping of permissions.  Each application could have its own set or several sets.  Through the provider model permission sets could also be shared across applications by pointing them at the same data source.  This abstraction model allows us as developers to have as many application permissions as we want without needing matching security roles for each one of them.

This abstraction of Permissions is something that applications like Rainbow portal did with a lot of database mapping.  The problem has been that some Roles are hard coded and there is not a consistent provider based system for managing permissions.  I plan to give this concept a thorough workout as I start working with Whidbey.  It could also be ported to ASP.NET 1.x if you had a Users and Roles store that you could tie it in with.

7/12/2004 11:45:39 PM (Mountain Daylight Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, July 07, 2004

One of the features of .NET 2.0 that I am excited about is the provider design pattern (This site is active but empty.  I plan to document as much as I can about providers on it as a way to help the community).  I decided that today I would begin looking at what it will take to use this in the applications we build at Idaho Commerce and Labor.  We plan to take advantage of this model as a way to share users, sessions, navigation and more across applications.  We need to investigate the security issues related to this of course.

So far I have discovered that the SQL providers can be installed with a utility called aspnet_regsql.exe in the %windir%\Microsoft.NET\Framework\v2.0.40607 folder.  I called my database Credentials since I was planning on working with Membership.  Now that is is created I see that it installs all of the SQL providers.

The tables I understand: Membership, Personalization, Profile, Roles, Site Counters, Users, UsersInRoles

There are other tables in the database as well that I assume are for some management and other purposes.  These include Applications, Paths, and WebEvent_Events.

What I do not see here is Sessions and Navigation.  I imagine that like .NET 1.x SQL Session state is a separate script to run.  More on that when I get to exploring the Session State provider.  As far as providers for navigation, I imagine that will be something custom I get to build.

I am now curious to see how this default SQL provider and its database will work when I point multiple applications at at.  What can and can't be shared.  Then I have to ask what should and should not be shared?

7/7/2004 11:25:00 AM (Mountain Daylight Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback