Here is an initial patch to combine the cas attributes roles module. It requires the patch in #1399304: Allow multivalue attributes to create a token(s) to represent the multiple values to be applied. I look forward to any suggestion you might have.

Comments

redndahead’s picture

Status: Active » Needs review
StatusFileSize
new3.81 KB
bfroehle’s picture

Status: Needs review » Needs work
+++ b/cas_attributes.admin.incundefined
@@ -69,6 +69,31 @@ function cas_attributes_admin_settings() {
+  $form['cas_attributes']['roles']['mapping'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Attributes'),
+    '#description' => t('Specify a token to use to match attributes with a role. Please put one per line.'),
+    '#default_value' => $managed_roles['mapping'],

Do I need to match the role id or the role name?

+++ b/cas_attributes.moduleundefined
@@ -70,4 +70,38 @@ function cas_attributes_cas_user_presave(&$edit, $account) {
+        $total_values = token_replace('[cas:attribute:' . $name . ':count]', $data);
+        for ($i = 0; $i < $total_values; $i++) {
+          $cas_user_roles[] = token_replace('[cas:attribute:' . $name . ':value:' . $i . ']', $data);

Could this be done more simply as:
explode(SEP, token_replace(['cas:attribute:' . $name . ':join:' . SEP . ']'))
for a proper separator?

bfroehle’s picture

+++ b/cas_attributes.admin.incundefined
@@ -69,6 +69,31 @@ function cas_attributes_admin_settings() {
+  $roles = user_roles(TRUE);

Add

  unset($roles[DRUPAL_AUTHENTICATED_RID]);

to remove an irrelevant option.

Also access to this whole fieldset should be restricted via:

'#access' => user_access('administer permissions')
redndahead’s picture

Status: Needs work » Needs review
StatusFileSize
new3.76 KB

Here are the changes. Won't be able to test them until tomorrow when I'm back at work.

redndahead’s picture

StatusFileSize
new3.81 KB

A fix for if no roles are selected.

bfroehle’s picture

+++ b/cas_attributes.moduleundefined
@@ -70,4 +70,37 @@ function cas_attributes_cas_user_presave(&$edit, $account) {
+    // Get our attributes
+    $attributes = token_find_with_prefix($role_mapping_tokens['cas'], 'attribute');
+    $cas_user_roles = array();
+    foreach($attributes as $name => $original) {
+      // If there is no token option then assume all of them.
+      if (strpos($name, ':') === FALSE) {
+        $cas_user_roles += explode('~&', token_replace('[cas:attribute:' . $name . ':join:~&]', $data));
+      }
+      else {
+        $cas_user_roles[] = token_replace($original, $data);
+      }

Rather than this, I think we should go back and rethink the array handling. For example, maybe we should add an option to the token handler which will return the raw array? The we could do something like

$tokens = token_scan(...);
$replacements = token_generate('cas', $tokens, $cas, array('raw_array' => TRUE));

Thoughts?

redndahead’s picture

I thought I tried to return the raw array and it returned an empty string. So I thought token was doing something, but that was early on and I could have been doing something wrong.

Unfortunately I'm in a bind to get this working really quickly, but I do want to do it right. So let's try to figure it out. Right now it's kind of special casing [cas:attribute:xxx] and instead of getting 1 value it's getting all. It would be nice to have an option to pull a raw array as it would make things a whole lot easier.

bfroehle’s picture

This is clearly difficult to architect correctly --- in particular we're using the token system for things it is not designed to do.

I see two paths forward:

1. Avoid the token system

Instead, just provide a simple UI:

Roles to Manage:
[ ] editor
[ ] creator
... etc

CAS Attribute(s) which contain role names, one per line.
+-----------------------+
| memberOf              |
| superSecretAttribute  |
|                       |
+-----------------------+

Then just do
$attributes = cas_phpcas_attributes($cas_name);, avoiding the token system completely.

2. Use the token replacement system:

Roles to Manage:
[ ] editor
[ ] creator
... etc

Roles names, separated by pipes
To get multiple values from a single attribute, use the following join syntax: [cas:attribute:memberOf:join:|].  Make sure to separate different tokens with a pipe as well.  Extraneous whitespace will be ignored.

+-------------------------------------------------+
| [cas:attribute:memberOf:join:|]                 |
|  | [cas:attribute:superSecretAttribute:first]   |
|                                                 |
+-------------------------------------------------+

Which do you think is better?

redndahead’s picture

Sorry for some reason I got logged out of d.o. and no new issues were showing up.

So here are my thoughts. Number 1 sounds best although it doesn't fit any of the other options on the page.

I'm thinking of adding a hook_cas_attributes_attribute_alter that will allow someone to manipulate the attributes returned from cas before we do the compare. So that you can return a single result only or if it's in a form of cn=tomato, ou=soup, dc=dinner, dc=food they can parse it and return soup as the group.

Right now with the array patch we special case [cas:attribute:xxxx] to be the first item in the array where in normal tokens it would be a comma separated value of the arrays. So doing that might not be best anyway.

What do you think?

bfroehle’s picture

Number 1 sounds best although it doesn't fit any of the other options on the page.

Yes, but it'd be easiest to implement on a deadline.

I'm thinking of adding a hook_cas_attributes_attribute_alter that will allow someone to manipulate the attributes returned from cas before we do the compare. So that you can return a single result only or if it's in a form of cn=tomato, ou=soup, dc=dinner, dc=food they can parse it and return soup as the group.

A few Q's regarding the hook:

(1): Would we first loop through the attributes to ensure that each one is an array?
(2): Would we have a similar hook for LDAP attributes? i.e. hook_cas_attributes_ldap_alter?

Otherwise I think this sounds brilliant!

redndahead’s picture

StatusFileSize
new4.2 KB

I think we can hold off on my deadline. It's best if we can get this right. Here is a patch that implements #1.

1) No we'll just handle it when building the array of attribute values. Have a look at the patch.
2) Yes we should. I think we can get away with using the same hook. But tell me if there are problems if we do. I don't have it in this patch, but you can see how it would be done with this patch.

redndahead’s picture

I'm starting to really need this now. Anything I can do to help continue this?

bfroehle’s picture

Sorry, this totally fell off my radar. :(

Is the patch in #11 ready to go? If you think so, I'll just go ahead and commit it.

redndahead’s picture

Just tested this again and it's working as expected. One thing I think we need is to maybe remove the word tokens in the description of the field. It's misleading in thinking that it uses the token module. Maybe replace with attributes

bfroehle’s picture

Yes. Also it'd be good if the description gave an example of the type of string by which we mean "attribute". Can you whip that up?

achantrill’s picture

Category: feature » support

Could you post a more complete description of what sort of CAS response you are expecting?

For instance, it looks like you can return a set of Role Names within a single attribute as a comma separated list, but I'm not getting that to work. I am finding a reference to [cas:attribute:$name:count] which makes me think you are looking for something like

<cas:authenticationSuccess>
	<cas:user>me</cas:user>
	<cas:attributes>
		<cas:email>me@school.edu</cas:email>
		<cas:group>Group</cas:group>
		<cas:group>Other Group</cas:group>
	</cas:attributes>
</cas:authenticationSuccess>

Using MultiRowJdbcPersonAttributeDao, you should get something like this:

<cas:authenticationSuccess>
	<cas:user>me</cas:user>
	<cas:attributes>
		<cas:email>me@school.edu</cas:email>
		<cas:group>[Group, Other Group]</cas:group>
	</cas:attributes>
</cas:authenticationSuccess>

but I'm not sure what exactly you are doing, and since attributes in CAS are non-standard (unless you are using SAML, which I don't think you are) I could really use a concrete authenticationSuccess response example.

Thanks!

redndahead’s picture

StatusFileSize
new4.24 KB

Here is a new patch

redndahead’s picture

@achantrill This module doesn't expect the attributes in any format. Since the cas module uses the phpCAS library that's how it gets it's attributes. You would have to ask the phpCAS library maintainers how they are handling the attributes.

bfroehle’s picture

+++ b/cas_attributes.admin.inc
@@ -69,6 +69,33 @@ function cas_attributes_admin_settings() {
+    '#description' => t('Specify the attributes to use for roles. Please put one per line. An example would be department or affiliations.'),

I think we'll need to be clearer that it isn't the token syntax. For example.

Specify the CAS attributes to use for roles, one per line. For example, department or affiliations. Do not use token syntax, as it will not be processed.

Otherwise I think this is ready to go. Do you concur?

redndahead’s picture

StatusFileSize
new4.31 KB

The clearer the better. :)

bfroehle’s picture

Version: 7.x-1.x-dev » 6.x-3.x-dev
Status: Needs review » Patch (to be ported)

In the interest of moving things along I've committed the patch in #20. Put follow-up things in new issues, I'll change this issue into a potential backport to 6.x if folks are interested.

Thanks for all the hard work (and patience!).

redndahead’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new4.38 KB

I don't think there are any differences in the code between d6 and d7. So I have just created a patch for d6. This hasn't been tested.

redndahead’s picture

Status: Needs review » Reviewed & tested by the community

I tested it out and it works great. I think you can commit this.

bfroehle’s picture

Status: Reviewed & tested by the community » Fixed

Thanks for the report. I've committed this to 6.x-3.x.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.