sfGuardPlugin with complex AND/OR credentials

1.4k Views Asked by At

I'm securing an action in security.yml. I want the user to have access if he has credentials (A and B) OR (A and C). Looking at the rather sparse docs I tried these combinations:

myaction:
  credentials: [[A, B], [A, C]]
  credentials: [[[A, B], [A, C]]]
  credentials: [A, [B, C]]

None of them work; [A, B] works, but that's only half the battle. Has anyone got something like this to work?

I'm using Propel 1.4.2 and sfActionCredentialsGetterPlugin. Thanks for your input.

Edit:

I did my testing without using the sfActionCredentialsGetterPlugin, just straight php in a template:

<?php $sf_user->addCredentials('A', 'C'); ?>
<?php var_dump($sf_user->getCredentials()->getRawValue()) ?><br><br><br>
<?php $cred_a = 'A'; ?>
<?php $cred_b = 'B'; ?>
<?php $cred_c = 'C'; ?>
<?php $cred_3 = array('B', 'C'); ?>
<?php $has_cred1 = $sf_user->hasCredential(array($cred_a, $cred_3)) ? 'true' : 'false' ?>
<?php $has_cred2 = $sf_user->hasCredential($cred_a, $cred_b) ? 'true' : 'false' ?>
<?php echo 'has cred1? '.$has_cred1 ?><br><br>
<?php echo 'has cred2? '.$has_cred2 ?><br><br>

I'm not getting anywhere.

There's a bit more info here: http://www.symfony-project.org/gentle-introduction/1_4/en/06-Inside-the-Controller-Layer#chapter_06_sub_complex_credentials

According to that, my third try above [A, [B, C]] should work!

Anyone?

Edit 2:

I tried a simple OR combination copied from the docs:

// security.yml:
credentials: [[A, B]]
// template:
$sf_user->hasCredential(array('A', 'B'), false)

Again, no dice. I posted a bugreport: http://trac.symfony-project.org/ticket/10036

I will post my temporary workaround as an answer here. Thanks guys.

4

There are 4 best solutions below

0
On

I need to move on to other things, so I'm posting my workaround to this issue here.

lib/Tools.class.php:

// check if the user has any of the given credentials
// (need this because sf OR credential combo doesn't work)
// superadmins always pass this check
// param credentials:   (string) single credential, or
//                      (array) flat array of string credentials
public static function hasAnyCredential($user, $credentials)
{
    if ( !is_array($credentials) )
    {
        return $user->hasCredential($credentials);
    }
    else
    {
        $test = false;
        foreach ($credentials as $credential)
        {
            $test = false;
            if ( $user->hasCredential($credential) ) $test = true;
            if ( $test ) break;
        }
    }
    return $test;
}

apps/mymodule/actions/actions.class.php:

// check if user has permissions B or C
// security.yml only has credentials: [A]
protected function hasBcPermission(myUser $user)
{
    return Tools::hasAnyCredential($user, array('B', 'C'));
}

This function is used to check action permissions and in the templates to hide inaccessible menus. Hope it helps someone with the same issue.

I'd still be glad to hear from anyone with a real answer!

1
On

Did you follow the Complex Credentials tutorial here: http://www.symfony-project.org/jobeet/1_4/Propel/en/13 ?

0
On

[A,[B,C]] becomes (A AND (B OR C))

so if you need ((A AND B) OR (A AND C))

i.e. equal to [A,[B,c]]

I needed (A AND (B OR C OR D))

I did [A,[B,C,D]]

This worked for me.

Remember!!

Each time you add a new level of square brackets, the logic swaps between AND and OR. So you can create very complex credential combinations, such as this:

credentials: [[root, [supplier, [owner, quasiowner]], accounts]]

          # root OR (supplier AND (owner OR quasiowner)) OR accounts

Also don't forget to refresh your credentials and check that you are assigned to A and B or A and C

You can check the details here. http://symfony.com/legacy/doc/gentle-introduction/1_4/en/06-Inside-the-Controller-Layer#chapter_06_sub_complex_credentials

0
On

Your code examples are a bit too detached I'm afraid. Can you also provide examples of how you are setting and checking the credentials? The problem might lie there and not with the definition itself. (also what is your security filter in filters.yml, and what exactly do you mean by "they don't work")

In the first snippet, option 2 and 3 will give a result as you expect. So any user trying to execute myaction will be allowed to do it only if he is Authenticated and has the credentials A and (B or C). Otherwise he will be send to the default login or secure action.

In the testing code there is an error which leads to wrong results:

<?php $has_cred2 = $sf_user->hasCredential($cred_a, $cred_b) ? 'true' : 'false' ?>

The hasCredential() accepts a credential or array of credentials as the first parameter and a boolean as the second. You pass two string credentials.

Every time you give examples of tests you have made give the information of what was the result you got and what should be the result you expect. This will help identify the problems.

In the third example you write a call to hasCredentials() but we don't know what credentials did you set on the user so we don't know what to check there.