Drupal core should create support for at least two more META-roles.

Meta Roles already defined in core

There are already 4 meta roles defined in different ways within the core of Drupal. They are:

  • Anonymous Users (i.e. $user->uid == NULL)
  • Authenticated Users (i.e. $user->uid != NULL)
  • Blocked Users (i.e. $user->status == 0 as stored in {users}.status)
  • Administrator (i.e. $user->uid == 1)

The last two roles are not defined in the {role} table, because their rights are implicit: Blocked users have the same rights as Anonymous users, and the Administrator (singular) has ALL the rights.

I would like to propose a more consistent approach to META-roles that would help resolve many user system and user.module related issues and also importantly stop providing an incentive for spammers to register phony accounts.

What about spammers' registration?

Spam is a nuisance to every webmaster. Any person who has administered a vanilla phpBB2 forum knows that spammers like to register phony accounts, just so that there is a link to their web site in the member list. Drupal has exactly the same flaw as phpBB in that it gives an incentive to spammers to register phony accounts with fake email addresses.

Already, several admins running a Drupal 4.7 web site have testified that spammers have already developped a tool to automatically submit registrations with fake emails in Drupal 4.7 sites. Particularly attractive to spammers are the site that offer users to fill in some profile textareas during registration and where the user profiles are visible by anonymous users.

Actually, the current wave of spammers' registration attack only aims to test the limits of Drupal, and to see how admins handle such spam. The spammers' robot always registers three accounts at the same time (within one minute, according to the time stamp and as testified by several Drupal admins). They use randomly generated names and email addresses (if those are not fake, it's only by accident). They automatically enter some text in each textareas that is presented to them during registration (when using the profile.module).
The first account will fill in all the text fields with plain text, the second with HTML, and the third with BBCode. They all enter links to non-existing web sites, either randomly generated, or typed in by a monkey jumping on the keyboard. Currently, their purpose is clearly to test the limits (and the spammability) of Drupal.

Drupal has a good captcha module (but captchas have their own limits. In my case, the use of the captcha module seems to have temporarily stopped spammers' registration, but it's only a matter of time before they break it. Also, remember: spammers are currently only testing the limits of Drupal. They are in testing mode, not in spamming mode. By harrassing admins with phony registration, they expect us to enable the captcha module so that they can test its limits, too.

A better use of META-roles in Drupal would provide an easy, low-tech (compared to captchas) solution that would make fake registration with fake email addresses completely pointless for spammers: they would have to use real email addresses they own, which at the very least would slow them down, but that's another story.

What Meta roles for Drupal?

The proposed META role list would make a better use of the {users}.status field in the data base.

  • Anonymous Users (i.e. $user->uid == NULL)
  • Unconfirmed Users (i.e. $user->status == 1)
  • Pending Users (i.e. $user->status == 2)
  • Authenticated Users (i.e. $user->status == 3)
  • Blocked Users (i.e. $user->status == 0)
  • Administrators (i.e. $user->status == 4)

Beside the use of the status field, there are three changes in this list compared to the first one.

First, we introduce the META role 'Unconfirmed Users' for the users who have just registered but not confirmed the registration using the code that was mailed to them. Such users would be treated like Anonymous users: the system will behave as if they don't have an account. In a site where anonymous users can view user profiles, accessing the profile of an Unconfirmed User would return a '404-file not found' error. Also, since Drupal allows Authenticated Users to change their email addresses after registration, such users would revert back to Unconfirmed users until the new email is confirmed, too.

Second, the new META role "Pending User" is for Confirmed users but whose account must be activated by an admin. Accessing their profile page would wield an "access denied (403)". This solves the issue (can't find it right now) saying that Pending Users waiting for admin approval see a message "you account has been blocked" when accessing their profile.

Third, if the User $user->uid == 1 is an Admin by default, there could be more than one Administrator set on any one site. This is an existing feature request and I believe many/most Drupal sites function with at least two admins: the geeky web developper, and the person the site is being developped for. The problem with the current approach, is that the first admin has to create a special admin role and remember to check all boxes in admin > access control each time a new module is enabled. Myself, many times I have been caught setting up a new module, and telling the other 'admin' what they can do, and they reply that they don't see what I'm talking about... only because I forgot to give them the access rights to the new module. With an administrator Meta tag, the status can be set for as many users as required, once and for all.

Difference with normal roles

Also, note the difference with normal roles. A single user can cumulate the rights of all of their roles. All users though will have one and only one META role. Being an administrator implies being an Authenticated user, and Pending/Unconfirmed users cannot login, so they are handled as Anonymous users.

The status code must be set so that we can control access by checking if $user->status >= 3; do stuff.

In the user/uid/edit page, the admin can set the following META roles:

  • Authenticated (or Normal) User
  • Blocked User
  • Administrator

They are radio buttons. Either none is set (for Unconfirmed users and Pending Users), or only one is set (for all other users).

The other META-roles are being implicitely handled by the system.

Better handling of phony and bona-fide registrations

This new set of META-roles allows the system to automatically handle fake registrations without the admin being involved in the process.

  1. The new user registers.
  2. A confirmation code is sent to the new users' email address. The account is set as "Unconfirmed" and the profile page doesn't exist at all (404) except maybe for the admins.
  3. If after a configurable length of time, the user has not confirmed the account, it is simply deleted altogether from the database by cron. The admins may not have been aware that all of this has been going on, which eases their job.
  4. If the account has been confirmed, and if new accounts are set to be moderated by the admins, then the account status is set as "Pending User". Only then is a watchdog entry created to alert the admins. Note that the captcha could be presented to the user only when they confirm their account (reducing server load) and not when they register. It also prevents spammers from using fake emails to practice decrypting the captchas as configured for a particular web site.
  5. Once the account has been approved by the admin, the user is alerted and a password sent to them. They are now "Authenticated users".
  6. Upon the user's first login, a welcome message can be presented to them (existing feature request)
  7. If the new accounts do not require admin authorization, then the recently confirmed user is set as "Authenticated user". A watchdog entry is created.

Another META-role can be conceived of: "Confirm new Email", for the users who change email. Their profile can still be viewable as usual by other users, but the user cannot login until the new email is confirmed, or the change reverted. This META-role would be placed between 'Unconfirmed Users' and 'Authenticated Users'.

A small fix for Drupal 4.7

Obviously all of the above should be for the coming 4.8 release, but for one small fix. Code-freeze being set for the 1st of September (!), Drupal 4.8 will not come out before October/November (?). It's a long time during which spammers can practice their favorite game: spam-registration.

Would Killes be willing to accept a small patch for 4.7 that prevents access to the user profile of a user who has never accessed the site (what would be a "Unconfirmed User" because the spammer used a fake email). A small fix would remove the only incentive to spammers to register fake accounts.

Patches

I agree to take on the responsability to provide a patch for this one, once the general principles have been agreed on, and the proper META-roles names/codes have been decided.

Ditto for a 4.7 patch, once Killes has agreed on the scope of that patch.

And also, I hope I am not taking on more than I can deliver... :-/

CommentFileSizeAuthor
#5 meta-2.diff.txt1.84 KBbeginner
#2 meta.diff_0.txt1.71 KBbeginner
#1 meta.diff.txt915 bytesbeginner
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

beginner’s picture

Status: Active » Needs work
FileSize
915 bytes

let's start with this patch.

beginner’s picture

FileSize
1.71 KB

Slightly clearer.

The ordering is done so that we can do:

if ($user->status >= META_AUTHENTICATED) {
  drupal_rejoice();
}

Here is the full block of code giving access to a user profile:

function user_view($uid = 0) {
  global $user;

  $account = user_load(array('uid' => $uid));

  if ($account === FALSE OR ($account->status =< DRUPAL_META_CONFIRM_EMAIL AND $user->status != DRUPAL_META_ADMINISTRATOR)) {
    return drupal_not_found();
  } elseif ($account->status =< DRUPAL_META_PENDING_APPROVAL AND $user->status != DRUPAL_META_ADMINISTRATOR) {
    return drupal_access_denied();
  }
  // Retrieve and merge all profile fields:
  $fields = array();
  foreach (module_list() as $module) {
    if ($data = module_invoke($module, 'user', 'view', '', $account)) {
      foreach ($data as $category => $items) {
        foreach ($items as $item) {
          $item['class'] = "$module-". $item['class'];
          $fields[$category][] = $item;
        }
      }
    }
  }
  drupal_set_title($account->name);
  return theme('user_profile', $account, $fields);
}
beginner’s picture

one line patch for 4.7:
http://drupal.org/node/64893

Dries’s picture

Explanation looks good. Haven't reviewed the code yet. Two quick comments:

1. Let's not introduce an adminsitrator role. The $user->uid is fine at the moment.

2. When I read the list of roles, the difference between pending and unconfirmed wasn't obvious. It wasn't until I read the explanation that the difference made sense. I'd like this to be obvious at first sight (i.e. be made more intuitive).

beginner’s picture

FileSize
1.84 KB

Thank you Dries for reviewing.

Let's not introduce an administrator role. The $user->uid is fine at the moment.

This discussion on Meta-roles is both the opportunity to improve the handling of the different registration steps, and to introduce one or two useful features. The possibility to have more than one administrator who has all privileges is one such useful new feature (it is also an existing feature request by someone else).

Also, it's the part that would be the easiest to implement. the attached patch shows the simple change in user_access(). Corresponding changes have to be made in other places. I can open a separate issue with a patch for only this particular feature.

function user_access($string, $account = NULL) {

  // Administrator(s) have all privileges:
  if ($account->status == DRUPAL_META_ADMINISTRATOR) {
    return TRUE;
  }

Most importantly, I think this feature would be more useful than you think. I don't know how drupal.org operates, but I would bet that many drupal sites (if not the majority) operate with more than one administrator: the developper who set up the site, and the one the site is being developed for. In the current setup, one needs to create a separate 'administrator' role, and remember to check all the boxes for each new module installed.

But if you still insist it's not needed/useful, I can live with it :)

When I read the list of roles, the difference between pending and unconfirmed wasn't obvious. It wasn't until I read the explanation that the difference made sense. I'd like this to be obvious at first sight (i.e. be made more intuitive).

You are right. That change was the object of my patch #2.
The roles now are:

// Defines the Drupal META roles.
define('DRUPAL_META_ANONYMOUS', 0);
define('DRUPAL_META_CONFIRM_EMAIL', 1);
define('DRUPAL_META_BLOCKED', 2);
define('DRUPAL_META_PENDING_APPROVAL', 3);
define('DRUPAL_META_CONFIRM_NEW_EMAIL', 4);
define('DRUPAL_META_AUTHENTICATED', 5);
define('DRUPAL_META_ADMINISTRATOR', 6);

Depending on how we use the meta-roles, the order would be important, so this needs to be discussed.

beginner’s picture

Priority: Critical » Normal

the most critical has now been dealt with.

sun’s picture

What's the status of this issue? Will this be committed for 4.8? These extensions to user roles are badly needed.

I am also confirming that we need a administrator role. Since we're working in a team, All of my Drupal sites are developed and maintained by more than one developer. Additionally we have a separate person for site administration of each Drupal site.

Some thoughts:

  • The description of this issue does not clearly state whether the corresponding actions for changing a user's role from 'Unconfirmed' to 'Pending Approval' or 'Authenticated' will be included in this patch, too?
  • Will administrators be able to decide whether users are automatically approved?
  • Will those meta user roles be separated in the user/edit form? One of these meta roles has to be set, while (an)other user role(s) may be additionally assigned.
  • I would propose to add the tabs 'Authenticated', 'Unconfirmed' and 'Pending Approval' to admin/user for filtering actual site users for administrators.
beginner’s picture

Title: META-roles, user registration handling and SPAM » META-roles, user registration handling and SPAM registration

The status is that nobody is working on it, now. I am busy with another big patch.
If you care to build up on my early patch, above, I will review your patch.

coreb’s picture

Version: x.y.z » 6.x-dev
Category: bug » feature

This would be very useful in the Drupal. I'm moving it out of x.y.z issue queue to the 6.x-dev queue. It also sounds more like feature request than a bug.

bradlis7’s picture

[subscribing]... I might try updating the patch on this later on, but I'm not making any promises.

sun’s picture

Version: 6.x-dev » 7.x-dev
mlncn’s picture

I think the simple matter of providing an administer role by default should be a separate issue, and could be done in D6.

The administrator role is a role I think the majority of serious users create themselves. Providing it in Drupal core (and nothing special about it, just a pre-made user-created role, if that makes sense) would be for the explicit purpose of letting modules set intelligent default permissions for this role

This will greatly increase Drupal's usability and ease of use. The enable a module and set permissions two-step shouldn't be necessary.

If anyone agrees that a simple administration role -- no new functionality, just so it's there for use when modules provide default permissions, please un-dupe http://drupal.org/node/182023 and comment there.

joelbox-Mondial-IT’s picture

Version: 7.x-dev » 5.7
Category: feature » support
Priority: Normal » Minor

I agree with the additional role detailing, it sounds like the right way forward.

Joel

beginner’s picture

Assigned: beginner » Unassigned

Please, don't change the settings for the whole issue.

macgirvin’s picture

Version: 5.7 » 7.x-dev
Category: support » feature
Priority: Minor » Normal

subscribe - referral from #171117: Regression: users without administer users permission can not access user profiles of users that never logged in , which points out the continued need for this patch. In that issue, we're seeing that the lack of this has made a mess of the user data in a hack effort to distinguish the unconfirmed users from everybody else.

catch’s picture

subscribe here too. This looks like the way to fix it.

salvis’s picture

Yes, this looks like a good plan. I'm not sure it covers Michelle's way of running her sites though.

IAC, the numbers assigned to the constants should not be consecutive. The administrator meta role went from 4 to 6 in two days, because new meta roles crowded in. Having these numbers change on a live site has the potential to create all sorts of problems. Especially the admin (if it becomes part of this) ought to be far away, like at 100.

Susurrus’s picture

@salvis: The roles are defined. Why would their number changing be an issue? Just make sure that you always use the constant, which should always be the case.

salvis’s picture

@Susurrus: From the OP:

The status code must be set so that we can control access by checking if $user->status >= 3; do stuff.

If you want to use operators like >=, you need to keep the sequence in a logical order.

OTOH, you can use all the names you want, but in the database there'll be numbers. This means you have to define your constants in such a way that you never need to change them.

Also, if push comes to shove, you'll be glad if you can look at a database table and figure out what it means.

RobLoach’s picture

What about removing the Meta-Role ideology all together and use roles instead? Add a "Blocked user" role and remove {user}.status. Then, we can expose certain permissions to blocked users in admin/user/access if we want to.

beginner’s picture

What's the term for that?
Why not use a binary sequence like 2, 4, 8, 16... with each number corresponding to a specific hurdle (registered, logged in, verified email, etc.)
Thus, we need only do binary comparison to see if a user has passed a given hurdle.

$user->meta_role = 0001101; // each bit represents one of the meta role discussed above.

RobLoach’s picture

Why not use a binary sequence like 2, 4, 8, 16

Bit fields or boolean flags are what you're referring to. $user->roles is kind of implemented the same method as what you're discussing here:

if (in_array('administrator', array_values($user->roles))) {

If we got rid of the meta-roles ideology all together, you could expose parts of Drupal to users that are blocked users (like allow them to see their user profile page, but nothing else). This means, remove $user->status and replace it with a "Blocked" role. Thoughts?

catch’s picture

I quite like the idea of a blocked role as opposed to the status flag.

I think what that means is a role beneath authenticated user. On forum sites it's quite common to temp-ban users for a day or few - you don't necessarily want to stop them using tracker/uid or private messages but need to stop people posting on the forums. In the Drupal handbook, if I understand it, one possible issue with giving edit rights to authenticated users would be there's no way to take it away from one specific user without banning them completely - so it might help for that kind of situation too.

I can think of two ways of doing it - a role which is sub-authenticated user, and which authenticated user inherits from - and could be used for blocked users and those who haven't completed accounts yet. Users would have to be moved into authenticated by default, with actions/triggers set up for the registration/blocking cases or something.

The other way would be a blocked role that doesn't inherit permissions from any other role - I can't think of any way the UI could work for this.

Anonymous’s picture

So a role.reverse column would be set to apply a reverse logic to the permissions?

While we're discussing this should we consider an administrator role as well, one that receives all permissions and remove the dependence of $user->uid == 1? This would work well with the role.reverse; a user could be assigned the administrator role and a role defining what the user can't do.

catch’s picture

So a role.reverse column would be set to apply a reverse logic to the permissions?

As in #23, I can't think of anything worse from a UI perspective (in fact I can't imagine what a UI would look like for it apart from horrible glimpses of checkboxes and weird backgrounds). It would solve some problems doing it like this, but I think it'd create much more.

I'm leaning towards two extra roles and slightly changing the behaviour of authenticated:

Anonymous - same as now

Sub-Authenticated - defaults to the same permissions as anonymous - all users get this role and this is where permissions are inherited from. We'd probably lock this one so users can't be taken out of it.

Authenticated -all authenticated users get this - but maybe from an action, and could be demoted from it. It's this one that replaces the meta roles. This'd allow the criteria for getting this role to be varied (require e-mail verification, fill out extra profile fields etc.), and it'd allow for extra intermediate roles to be added since there wouldn't be anything all that special about authenticated user any more apart from some default settings and the permissions that it currently has in core.

Admin - has all permissions added by default, replaces user/1 special casing, user/1 is put into this role by the installer.

Probably big holes in those ideas but fwiw.

Anonymous’s picture

Speaking of the permissions checkboxes, ugly lot and every module adds more. This needs a change to two mutiselect boxes with "Add->" "<-Remove" buttons. The Add-> button would give the selected permissions and the <-Remove button would take away the selected permissions. A bit off-topic but related.

Sub-Authenticated ... How about naming it Pre-Authenticated? Thinking more about it, I don't know that it provides much benefit. I think I would rather just check or uncheck the boxes on the Authenticated Role and not inherit anything from Anonymous. We're trying to remove the hardcoded preconceived ideas and give all the decision to the administrator.

Admin ... Let's spell it out as Administrator for the translation factor.

I still like the role.reverse idea, especially when giving the user the Administrator role to say that the person has rights to administer everything except these but I can live without it.

David_Rothstein’s picture

Would it be possible to combine the different ideas here and do something like the following?

  • Keep @beginner's original idea of expanding the $user->status codes, but don't associate them directly with any roles/meta-roles. Even if you don't want to give a user any new permissions immediately after they have completed a verification step (e.g., confirming their email address), it still can be useful to keep track of this information and know they have done it -- that's the basis of a solution for the profile spam problem, right?
  • Instead, associate $user->status codes with role changes only through a "trigger-action" kind of system, as @catch suggested.

The administrative UI for managing the user registration process would then look something like the following (basically just an ordered list of status changes, each of which can optionally trigger a role change):

  1. "account is created" => user gets put in role A
  2. "administrator approves account" => user gets put in role B
  3. "user confirms email address" => user gets put in role C

When registering for the site, the user would be presented with the above steps in order, and each time they complete a step their $user->status code would change. (In the long run, it might actually be possible to let them do these steps out of order too, or let the site admin change the order and add new steps via contrib modules, etc, but maybe that should be saved for later because it would get complicated.)

In keeping with current Drupal behavior, any of these steps could be disabled (a.k.a. made "not required"), except the first one, of course. Furthermore, the administrator would be allowed to change the role assigned to any step, or not have a role assigned to that step at all. If the user has gone through some registration steps but has not yet been assigned any roles, then there could be two possibilities:

  • the user is not allowed to log in [this would be the default]
  • the user is allowed to log in but gets the same permissions as anonymous

I think doing it this way might allow the assigned roles to be treated exactly like normal Drupal roles; they could be created by the site admin if desired and would not have to be hardcoded in. At the end of the registration process, a user would simply have the combined permissions of all the roles they picked up along the way. Does that seem like it would work?

I'm not sure what to do about a single hardcoded role for "authenticated" users, though:

  • One possibility is @catch's idea in #25, where a role would be hardcoded into the first "account is created" step above, and all logged-in users would always have that.
  • Another possibility is to hardcode a role at the end, which all users would get once they have finished the registration process. I guess that is closest to the current Drupal behavior.
  • Finally, the most radical idea would be to hardcode nothing. So a default Drupal installation would look like this:
    1. "account is created" => [no role is assigned]
    2. "user confirms email address" => user gets put in "authenticated users" role

    But the "authenticated users" role that ships with Drupal wouldn't be special, and it could be unassigned, deleted, etc.

Not sure what the right option is here; they all seem to have strengths and weaknesses. The last one is probably the most intriguing, but also the most tricky.

Also not sure what to do with admin-created accounts... they should definitely get the "account is created" and "administrator approves account" $user->status codes (and any roles associated with them), but I'm not sure about anything else. It doesn't feel right to mark their email address as having been validated when it has not.

Anyway, just some (rather long) thoughts. I suspect there are some big holes in these too, but this is a tough problem ;)

David_Rothstein’s picture

As for blocked users: I think there is definitely a valid use case for something similar to what Drupal already does, where you have a single flag that blocks the user but doesn't change anything else. In the current context this would mean that their status and roles stay the same, but they aren't allowed to log in.

However, on top of that, the idea of a "blocked user" role (really more like a "demoted user") makes sense, and I think it would be possible to implement; you would just have to unassign them from any roles they picked up along the way (during the registration process) and reassign them to a new, more limited one, right? Demoting a user to a lower status (e.g., marking their email address as unvalidated) could also work here, probably. I'm not sure if that is something that belongs in core or contrib, though.

David_Rothstein’s picture

One more thought: I personally think "authenticated users" is already a bit of a confusing role name, but it would have the potential to be even more misleading and inaccurate if some of the ideas here were to be implemented. I'm not so sure if "sub-authenticated" or "pre-authenticated" are good either (?).

How about something like "site members"??? Not sure it's great, but it explains more who the users are than how they got there, and I think that's arguably better. (Then maybe "anonymous users" could become "nonmembers" too, although I'm less sure about that idea.)

Anonymous’s picture

How about something like "site members"??? Not sure it's great, but it
explains more who the users are than how they got there, and I think
that's arguably better. (Then maybe "anonymous users" could become
"nonmembers" too, although I'm less sure about that idea.)

Ick, let's not dumb down the users. Administrators should already know what authenticated and anonymous users are.

Anonymous’s picture

As for blocked users: I think there is definitely a valid use case for something similar to what Drupal already does, where you have a single flag that blocks the user but doesn't change ...
However, on top of that, the idea of a "blocked user" role (really more like a "demoted user") makes sense ...

A user.module permission could be "access site" or maybe "access login" to stop the user from logging into the system if the user is a member of a role that doesn't have this permission set.

But we need to know if user.visible is TRUE for the whosit blocks and the user profile pages; we may want to see the user but not allow the login. We may want to not see the user but allow the login. We may want all but one user visible. We may have a user invisible and not able to login. A user.visible column along with user permissions of "access site" gives the most flexible combination. The "access site" permission would easily implement the "blocked user" role.

Anonymous’s picture

The administrative UI for managing the user registration process would then look something like the following (basically just an ordered list of status changes, each of which can optionally trigger a role change):

1. "account is created" => user gets put in role A
2. "administrator approves account" => user gets put in role B
3. "user confirms email address" => user gets put in role C

Couldn't this be handled in a module; such as Advanced User or even one called User Actions?

David_Rothstein’s picture

Ick, let's not dumb down the users. Administrators should already know what authenticated and anonymous users are.

OK, I think I agree with you about the anonymous users, at least. The concept of "anonymous user" does have a clear technical meaning which we shouldn't try to obscure with friendlier terminology... so I retract my idea of changing that to "nonmembers" ;)

But for "authenticated users", I'm not sure. It's technically an accurate name now, but with many of the ideas that have been suggested above, that would change. Right now "authenticated users" is its own role because Drupal is designed so that all logged-in (a.k.a. "authenticated") users are equal at some base level. But I think the point of most of the above discussion is that the distinction should not be such a binary one. If your site wants to let users log in and play around with their personal settings after they have created an account, but not let them do anything more special until they have actually clicked on the validation link in their email, then the concept of an "authenticated user" role may legitimately cause confusion for you.

Here's a more concrete example: If we went with my suggestion, then on a fresh Drupal installation you would go to the permission page and have two roles to assign permissions to: "anonymous user" and "site member". If the concept of "site member" is not applicable to you, you could delete this role or rename it, etc, since it wouldn't be hardcoded. But otherwise, you would only have one main question to answer while you're on that page: "What permissions do I want my site members to have?"

Then you would head over to admin/user/settings, and the question you would answer there is: "What do users have to do in order to become site members?" The default settings would look like this:

  1. "account is created" => [no role is assigned]
  2. "user confirms email address" => user gets put in "site members" role

If you then decide that you'd also like to approve everyone by hand before they can become "site members", you just change it to this:

  1. "account is created" => [no role is assigned]
  2. "administrator approves account" => [no role is assigned]
  3. "user confirms email address" => user gets put in "site members" role

And if you later decide you'd like people to have access to a limited set of permissions before being approved, you could just create a new role and change the settings to this:

  1. "account is created" => user gets put in "probationary members" role
  2. "administrator approves account" => [no role is assigned]
  3. "user confirms email address" => user gets put in "site members" role

From my point of view, this wouldn't be dumbing down Drupal at all, but rather making the terminology more accurate and the admin interface more flexible and intuitive... what do you think?

Couldn't this be handled in a module; such as Advanced User or even one called User Actions?

You may be right. Actually, I think the LoginToboggan module does a very limited version of this (with "pre-authenticated" users) now, although I've never looked at how it implements it (?). I just thought that @catch's idea of assigning roles via a trigger-action-type system was cool enough and general enough that maybe it belonged in core, but I'm not sure. (If you do leave this to contrib modules, then the question doesn't necessarily become any simpler, though; at that point core definitely need to hardcode an "authenticated users"-like role somewhere in the process, and exactly when to do so still seems like it's unsolved, based on the above discussion?)

David_Rothstein’s picture

A user.module permission could be "access site" or maybe "access login" to stop the user from logging into the system if the user is a member of a role that doesn't have this permission set..... The "access site" permission would easily implement the "blocked user" role.

I guess this might work. But I don't think it's ideal for the following case: Suppose you have an important user who has been assigned a bunch of different roles on your site. You suspect their account has been hacked into so you decide to block it temporarily while you sort things out. Once you're satisfied everything is OK, you want to restore the account exactly back to the way it was. A simple boolean "blocked" flag as Drupal does now is perfect for this... but if you implement blocked users as a role only, then it's much more of a pain, and you need to remember exactly which roles you had them in and assign them back to these roles by hand, etc... Does that make sense?

But we need to know if user.visible is TRUE for the whosit blocks and the user profile pages; we may want to see the user but not allow the login. We may want to not see the user but allow the login. We may want all but one user visible. We may have a user invisible and not able to login.

This seems reasonable, but can't the value of "user.visible" just be a setting that depends on the others? As you say, different sites might have different policies for when they want the users to be visible, but it seems to me like these policies would all depend on $user->status (e.g., whether or not the user has clicked on an email validation link) or "$user->blocked" (e.g., whether or not the user has been blocked by the site admin), etc. So would "user.visible" work as a setting, rather than something that needs to be stored in the database directly per-user? I'm not sure...

Shai’s picture

I'd like to bring up a related issue.

There is a problem with "authenticated user" functioning as a "role" because it doesn't behave like other rules. Whenever "authenticated user" is selected on a list (e.g. permissions, block visibility, any module that applies functionality by role) it is a big usability issue that authenticated user behaves differently. Selecting "authenticated user" in such a situation applies to all the other roles except anonymous user.

This is a problem when an admin wants to apply some settings to authenticated users who have no other role, but not apply those settings to authenticated users with other roles. This is only possible in situations, such as block visibility, where there is the possibility to create the desired result with custom php. This is not good for non-programmer site admins.

This situation also encourages module developers to create functionality that is not consistent with Drupal's "opt-in" approach toward role settings (e.g. with permissions you click on roles to get privileges, you don't click on boxes to restrict privileges). One example is the Google Analytics module. Prior to version 1.4 you clicked on roles to exclude those pages from receiving the Google Analytics tracking code. That solved the problem of targeting authenticated users who were not assigned any other role. You just check all boxes except anonymous user and authenticated user. But now that UI was at odds with Drupal's general approach on this matter, and the GA maintainers switched the logic beginning with version 1.4. And now they are stuck with the problem I'm describing here. (Read abut this at: http://drupal.org/node/258981)

Relating this back to the issues at hand here in this thread, I really like the idea of meta-roles related to user status. We already have two meta roles, anonymous users and authenticated users. It just beefs that up. It also highlights the fact that these aren't real roles at all.

Durpal would need to require default roles be set up for anonymous and authenticated users. Site admins would be required to create those two roles at set-up time.

The meta-roles related to user status would come in handy in various ways programatically. But the admin interface for most, if not all, situations regarding visibility of functionality could be universally "opt-in".

David_Rothstein’s picture

I was thinking about this a little more, and maybe this whole issue is too broad to deal with in a single patch....

As @earnie pointed out, a lot of the role-related stuff could be dealt with in contrib modules. Regardless of whether that's a good idea, it definitely seems to argue for holding off on the "meta-roles" vs "roles" vs "trigger/action" stuff for now and saving that for a possible followup patch.

So how about the following plan for starters?

  • Add a new element to each user, call it $user->validation, to keep track of the validation steps that user has gone through. Probably implement this an array of flags or via bit fields, as discussed in #21 and #22 above, perhaps with just two possible values for now: "email address verified" and "account approved by administrator"?
  • Add a good API for finding out if a user has passed a certain validation step, editing the steps they have passed, etc.
  • Add a hook so modules can respond to the fact that a user has passed a validation step.

Let's leave $user->status as it is now (binary flag for whether the user is blocked), since that's kind of a different beast....

And that's all (for now); the rest could be saved for a followup patch.

Comments?

Shai’s picture

I like Catch's approach in comment 25. When he writes:

authenticated users get this [role] - but maybe from an action, and could be demoted from it... there wouldn't be anything all that special about authenticated user any more apart from some default settings and the permissions that it currently has in core

Catch's approach here seems to be to try to get the role system to handle both status and role. I think it would be cleaner to separate the two.

Each status could trigger assignment to a default role. But once that assignment is made, there is no further intrinsic linking between the status and the role. Changes in status can also trigger unassignment of roles. Permissions and visibility settings, however, would be purely based on roles, not status. That's what solves the problem of a status trumping the role system (the case where checking "authenticated user" as a role forces inclusion of ALL authenticated users, even those of a particular role that the admin wants to exclude).

I think the talk of the role.reverse column is the wrong way at trying to solve the the same problem I'm concerned about.

Catch's point about the reversibility of a role assignment that is initially triggered by a status, is absolutely key.

That's it for now.

Shai

catch’s picture

OK I think I can agree that there's two issues here:

1. Having a record of the various statuses of users - $has_account $has_validated_email $has_logged_in - we ought to make this extensible somehow so you can have things like $has_posted_content as well.

2. Using these statuses to define which roles users get put into programmatically instead of hard coding authenticated user.

However, I think removing the hard-coding of authenticated user provides a very good implementation of the API in 1 and it might be hard to split them into two issues. fyi I mentioned actions/triggers since it's already got a track record for changing states of things in workflow, and because it's an existing API that's already in core.

As to whether users are visible or not (the original prompt for bumping this issue) - why not have core decide one or composite status which it uses to decide ($has_validated_email && $has_logged_in) - and again set this up so contrib can intervene. I think this needs to be removed entirely from the logic which determines what users with those various statuses can do themselves (i.e. the roles system).

edit: cross-posted with Shai, but seems like we're looking at this in a similar way (at least as it stands now)

macgirvin’s picture

I think we may be risking things by tying too much work flow and state logic into core. I'd like to simplify. Currently we have one bit that indicates blocked or not. An access timestamp is being over-ridden to get an additional bit of information, that of profile visibility. Separating that one additional bit, say user->visible would solve many of the issues that we're trying to solve although it deviates from the issue title. user->visible designates whether or not a profile can be retrieved for the person AND whether they show up in any member listings. It's a well defined flag with a well defined purpose.

Core logic would set it automatically on first login (!user-access). In any event it's available in the profile for over-ride.

Site admins need to be able to see everybody, regardless of visibility setting - else they wouldn't be able to change it.

Perhaps one more change to make it all work smoothly is that for exists and !visible and !admin, show a polite message that the profile cannot be viewed rather than the harsh 404.

If you think this needs another issue, let me know and I'll split it off. I'm going after the core problems and leaving the abstraction of roles for another day.

David_Rothstein’s picture

Thinking about the $user->visible stuff here definitely makes sense to me.

I don't think $has_validated_email should be used (as suggested in #38) unless we provide a configuration option to turn it off... sites don't always require users to validate their email address, so this would be bad because all users on those sites would then be invisible.

I'm also not sure $has_logged_in by itself is good either (as suggested in #39)... what do you do with admin-created accounts that haven't logged in yet? Don't you run into the same sorts of problems as in #171117: Regression: users without administer users permission can not access user profiles of users that never logged in ? Maybe we can make it a setting: Leave it up to the site owner to decide whether or not users need to have logged in in order to be visible. Would that work?

David_Rothstein’s picture

As for the main track of this issue, it seems like a few of us are in agreement about how to proceed. I would just say let's try to see if it can be done in two medium-sized patches rather than one gigantic one, although if it winds up being too tangled together, then do it all at once. I'm definitely in favor of getting rid of the hardcoded "authenticated user" role as a great use of the API and an immediate next step, but I just worry that if we try to tackle it all at once, none of it might actually get done....

About the roles, though, @catch wrote:

fyi I mentioned actions/triggers since it's already got a track record for changing states of things in workflow, and because it's an existing API that's already in core.

I'm curious how much you think the existing API can be used here? I'm guessing we can definitely use Actions, but not the Trigger Module itself (since it's not a required module and might be overkill anyway). Instead, the user status changes would have their own very primitive "trigger" implementations. Is that what you were thinking? (I don't know a whole lot about the details of Triggers/Actions myself, which is why I'm wondering.)

@Shai wrote:

Changes in status can also trigger unassignment of roles.

Can you think of a good user interface for that? I worry that it might be a lot more complicated if we allow this possibility too, although for super-extra-flexibility it would definitely be nice... I'm guessing you can get the main flexibility that you need even with just a limited set of options (where a status change can only add a user to a single role but not unassign roles), but I'm not sure... I haven't thought about this in depth myself.

catch’s picture

David - extra states - I think we should store sensible defaults, use those various states to determine a sensible default for visibility and/or roles in core, and let contrib handle a UI (for either or both).

actions/triggers - I probably know less about actions/triggers than you, was just an idea, may or may not turn out to be a good one.

salvis’s picture

@macgirvin: The issue of whether users that have never accessed the site should be visible is the topic of the other thread. If access weren't clobbered, we wouldn't need an additional invisible bit, and not clobbering access is important beyond deciding whether users should be visible or not. That's the topic of #171117: Regression: users without administer users permission can not access user profiles of users that never logged in .

This thread here has a much broader scope, and you're not simplifying if you try to focus this thread on the topic of the other thread.

Anonymous’s picture

@David in #34:

I guess this might work. But I don't think it's ideal for the following case: Suppose you have an important user who has been assigned a bunch of different roles on your site. You suspect their account has been hacked into so you decide to block it temporarily while you sort things out. Once you're satisfied everything is OK, you want to restore the account exactly back to the way it was. A simple boolean "blocked" flag as Drupal does now is perfect for this... but if you implement blocked users as a role only, then it's much more of a pain, and you need to remember exactly which roles you had them in and assign them back to these roles by hand, etc... Does that make sense?

The "Access Site" permission would be unset in a role and a blocked user would be assigned the role. To reset you remove the role from the user. This has a benefit if you want to assign a role for temporary access and you set and unset the Access Site permission in the role at will.

This seems reasonable, but can't the value of "user.visible" just be a setting that depends on the others? As you say, different sites might have different policies for when they want the users to be visible, but it seems to me like these policies would all depend on $user->status (e.g., whether or not the user has clicked on an email validation link) or "$user->blocked" (e.g., whether or not the user has been blocked by the site admin), etc. So would "user.visible" work as a setting, rather than something that needs to be stored in the database directly per-user? I'm not sure...

I'm assuming that since using a permission to block the user, a status to do the same isn't necessary. Blocked and visible are different though. Visible to others can only be controlled within the user data and not the permissions of a user.

Anonymous’s picture

RE: actions/triggers and roles

What about adding a column in roles (perhaps a new control table) that indicates that an action must have happened before the role is triggered? This allows greatest control of the user and the permissions the user is allowed to have.

catch’s picture

The "Access Site" permission would be unset in a role and a blocked user would be assigned the role.

If you did something like that now, they'd still have the 'access site' permissions - because roles are cumulative.

macgirvin’s picture

@salvis #43

#171117: Regression: users without administer users permission can not access user profiles of users that never logged in is about a regression, caused by a quick hack to solve the SPAM profile problem, which is referenced in the title to this issue -

META-Roles, user registration handling and SPAM registration

We still do not have a viable resolution for the original problem and META-Roles cannot solve it without revamping a lot of permissions infrastructure. This likely pushes it out a number of years and offers no relief to existing sites. We would still need a visibility setting to solve the problem, no matter what roles are built-in/enforced - as it requires a per-user setting on whether or not a profile should be displayed (to the anonymous role). The permissions or role of the person owning the profile aren't relevant to that decision.

Blocking a user is part of the original discussion but not reflected in the issue title. This can be dealt with relatively easily. If one is blocked, they shouldn't have a separate role at all, but merely be prevented from logging in (thereby giving them the same rights as anonymous). On a site with open registration, they'll just get a new login in any case and go back to their disruptive behavior.

Dries has already shown disfavor with a default admin role so that isn't going to fly unless a compelling argument is presented.

So what specific issues are we trying to solve? And is META-Roles the right way to do any of them? I'm interested in solving issues, not generating useless infrastructure.

Anonymous’s picture

@catch #46: D'oh... Of course... The permission would need to be 'blocked access' or we need a role.negate or role.reverse column and use 'access site'.

catch’s picture

I'd be -1 any 'negative' permission or 'negative' role - it'd be an absolute UI nightmare.

sun’s picture

FYI: http://drupal.org/project/role_login looks like a quite interesting approach for blocking access for users in a certain role. Based on the idea of this module, I could even imagine a simple user permission "allowed to login" (or negated) that can be enabled for various user roles. That would allow for total freedom in setting up a Drupal site and its behavior.

Also: I hereby retract my statement in #7 - I do not believe we need an administrator role. We need far more user permissions instead. For example, our first step after installing Drupal is always the same: Create a "developer" role that has sufficient permissions to install/uninstall modules, alter user permissions aso. and assign that role to all developers.

Anonymous’s picture

logintobabban also provides a ``pre-authorized'' role interface where you can assign a role that gives not quite authenticated role. You then just move the user to the authenticated role on approval of the user. Maybe this is enough of a feature.

christefano’s picture

As Rob Loach says in his comment (#20), why not have designated roles instead of user states? I can think of several use cases for it, not the least of which is to confine blocked users to specific role-based permissions.

sun’s picture

Version: 7.x-dev » 8.x-dev
valthebald’s picture

Issue summary: View changes
Issue tags: +needs relevance check

Is it still relevant?

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dpi’s picture

Status: Needs work » Closed (outdated)

The issue proposed to overload the $user->status property with various state constants. Modifying status from a boolean to integer constants.

Originally this issue outlined the following Drupal behaviour for how it determines a "meta role":

Meta Roles

Anonymous Users

  • Evaluated by (Drupal 4.7): $user->uid == NULL
  • Proposed: $user->uid == NULL)
  • Drupal 8: $user->isAnonymous() (Internally: $user->uid == 0). A special anonymous user role exists.

Authenticated Users

  • Evaluated by (Drupal 4.7): $user->uid == NULL
  • Proposed: $user->status == 3
  • Drupal 8: $user->uid != NULL (Internally: $user->uid > 0). A special authenticated user role exists.

Blocked Users

  • Evaluated by (Drupal 4.7): $user->status == 0
  • Proposed: $user->status == 0
  • Drupal 8: $user->isBlocked() (Internally: $user->status == 0)

Administrator

  • Evaluated by (Drupal 4.7): $user->uid == 1
  • Proposed: $user->status == 4
  • Drupal 8: Assign 'Administrator role', this role gets all permissions automatically. Permissions are emphasised over user 1.

Unconfirmed

Role proposed in summary

'Unconfirmed Users' for the users who have just registered but not confirmed the registration using the code that was mailed to them.

  • Proposed: $user->status == 1
  • Drupal 8: User is blocked (default behaviour), email is sent with activation code, no record is made.

There are multiple ways of doing this in contrib already.

You can choose to assign a role to new users, once they have been confirmed you can remove this role.

Or the inverse, cnce a user activates the account, you assign a role.

Pending Users

Role proposed in summary

"Pending User" is for Confirmed users but whose account must be activated by an admin.

  • Proposed: $user->status == 2
  • Drupal 8: User is blocked (default behaviour), no email is sent to admin, no record is made.

Conclusion

This issue summary is quite heavy, with no real sense of direction. The two "meta roles" can be discussed in this issue: #426688: Record "pending admin approval" state.

Closing this issue since the 'status' field is clearly boolean.