I finally tracked down the source of a very strange bug in our local DNN installation and I figured I'd save anyone else, who happened to have the same error, the time and effort of tracking it down for themself. Turns out, I may have found a bug in two core stored procedures along the way to boot.
DNN VERSION: 3.3.4
OBSERVABLE PROBLEM: User Roles suddenly were being displayed quadrupled in both the "Admin --> Security Roles" page as well as within both the Page Level and Module Level "Settings" pages. Interacting through the user interface and setting or unsetting Public/Auto Assign flags would update all 4 duplicated roles. Trying to delete any one would delete all 4 as well. Viewing the "Roles" table via Enterprise Manager revealed no duplication in the table itself.
CAUSE: The reason the roles were being duplicated was a result of the combination of the following two things:
1) How role attributes are joined to the Frequency List accessible on the "Hosts --> Lists" page.
The list of roles on the problem pages was being returned by one of two stored procedures. The following is the source for the “GetPortalRoles” stored procedure (I've omitted the extraneous select fields):
CREATE PROCEDURE dbo.[GetPortalRoles]
@PortalId int
AS
SELECT <List of Fields to Return>
FROM dbo.Roles R
LEFT OUTER JOIN dbo.Lists L1 on R.BillingFrequency = L1.Value
LEFT OUTER JOIN dbo.Lists L2 on R.TrialFrequency = L2.Value
WHERE PortalId = @PortalId
OR PortalId is null
ORDER BY R.RoleName
The thing to notice is that the "Roles" table is being joined on the "Lists" table twice. Once for Billing Frequency and a second time for Trial Frequency. Leaving roles with their default settings results in an 'M' and 'N' inserted into the "BillingFrequency" and "TrialFrequency" fields of the "Roles" table respectively. The 'M' standing for "Month(s)" and the 'N' for "None"
2) The second factor involved was just blind luck
I had given a developer an assignment to create an "Ethnicity" list on the "Host --> Lists" page. It was going to be used in the same way that the country list is currently used to populate the country drop down control. As his source, I had him copy the hard coded list that our University currently uses in it's forms. In that list, the University associates display names to single character codes. As you can probably guess, 'M' is in the list associated with "Asian: Cambodian" and 'N' is associated with "Pacific Islanders: Samoan".
Because the GetPortalRoles and GetRolesByGroups stored procedures were joining the roles table on the lists table by equating the default 'M' for Billing Frequency with the existence of 'M' as a list value, the roles were being doubled since two existed.
By the same logic, the test for the default Trial Membership 'N' on the list table was resulting in the quadruple display of each of the roles that was observed.
SOLUTION: As a quick fix, I made the following modification to both the GetPortalRoles and GetRolesByGroups stored procedures.
CREATE PROCEDURE dbo.[GetPortalRoles]
@PortalId int
AS
SELECT <List of Select Fields>
FROM dbo.Roles R
LEFT OUTER JOIN dbo.Lists L1 on L1.ListName = 'Frequency' AND R.BillingFrequency = L1.Value
LEFT OUTER JOIN dbo.Lists L2 on L2.ListName = 'Frequency' AND R.TrialFrequency = L2.Value
WHERE PortalId = @PortalId
OR PortalId is null
ORDER BY R.RoleName
This has fixed the problem for me so far but I am completely open to any better solutions. This little Easter Egg caused me a bit of grief and I was content enough when I finally figured it out to make my first post on these boards and share it.