How to unsecure admin generated modules in Symfony

You gotta love the admin generator… There’s only one problem: it’s secured by default (according to the symfony site).
But I want to use these modules in a non-secured environment.
Adding credentials: [] in the admin generator does not work… Why?
Look at your automoduleactions. You’ll find a preExecute function:

  public function preExecute()
  {
    $this->configuration = new eventGeneratorConfiguration();
 
    if (!$this->getUser()->hasCredential($this->configuration->getCredentials($this->getActionName())))
    {
      $this->forward(sfConfig::get('sf_secure_module'), sfConfig::get('sf_secure_action'));
    }
 
    $this->dispatcher->notify(new sfEvent($this, 'admin.pre_execute', array('configuration' => $this->configuration)));
 
    $this->helper = new eventGeneratorHelper();
  }

This code is always executed before any action.

if (!$this->getUser()->hasCredential($this->configuration->getCredentials($this->getActionName())))

the getCredentials function:

  public function getCredentials($action)
  {
    if (0 === strpos($action, '_'))
    {
      $action = substr($action, 1);
    }
 
    return isset($this->configuration['credentials'][$action]) ? $this->configuration['credentials'][$action] : array();
  }
}

The problem is that hasCredential(array()) returns false.
My solution:
Override the hasCredential function in myUser

  public function hasCredential($credential, $useAnd = true)
  {
    //for usage in generator => + as credential will return hasCredential=true (even if user has no credentials at all)
    if($credential === true) return true;
    //btw => you could have checked for an empty array of credentials which is what the generator is returning
    return parent::hasCredential($credential, $useAnd);
  }

Now to make it work, put in generator.yml

  config:
     actions:
        _delete:        { credentials: admin }
        _list:            { credentials: + }
        index:           { credentials: + }
#        _new:         { credentials: + }
#        _edit:         { credentials: + }

Ps: You could also use false & -

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

11 Responses

January 26, 2009
Luciano

Wouldn’t it be easier just to unsecure the actions you want via the apps/frontend/modules/mymodule/config/security.yml as stated here?
http://www.symfony-project.org/book/1_2/06-Inside-the-Controller-Layer#Action%20Security


January 27, 2009

Well Luciano,

I tried that too, but it does not work (in this case)… The problem is that the generated preExecute action looks at your generator.yml and not the security.yml to forward you.


January 27, 2009
Luciano

I’ve just followed these steps to reproduce your issue using sf_sandbox 1.2.2:
-I created a new propel admin module.
-I secured the app, modifying
/sf_sandbox_1_2/apps/frontend/config/security.yml with these values:
default:
is_secure: on
-I tested it in the browser, i was asked to login (so far so good)
-I created /sf_sandbox_1_2/apps/frontend/modules/{module_name}/config/security.yml with this content:
all:
is_secure: off
and then tested it again in the browser… and voilà I was no longer asked to log in, I didn’t touch anything in config.yml nor in actions.class.php of my module.
Could it be something fixed after you downloaded your symfony?


January 27, 2009

Hmmm, that’s strange.
Few questions:
1) Did you use propel:generate-admin? I guess you did…
I’m asking because the method you’re describing is the default symfony behaviour (as you would expect). But that’s not what’s happening here… :s
2) You’re probably not using sfGuardPlugin in your sandbox. THAT could be the problem! :)
3) hasCredential(array()) is probably returning true in your case, instead of false?
That’s what the preExecute action is returning anyway (if no credentials defined in generator.yml)…

I’ll try to find out if the sfGuardPlugin is indeed the problem…

PS: I’m using symfony release_1_2_2


January 27, 2009
Luciano

Answers… but not to all :(
1)Yes I did use the propel:generate-admin.
2)I didn’t know you were using sfGuardPlugin.
3)Without sfGuardPlugin hasCredential() returns true, but with sfGuardPlugin it returns false, mmm why is that?? Simple beacuse hasCredential() checks differents things in sfGuardSecurityUser and in sfBasicSecurityUser.
The thing is that when you extend sfGuardSecurityUser, hasCredential() checks if there is a sfGuardUser walking around, and as we don’t want one of those (this is the whole point) it just returns false. I think perhaps there is something wrong, because the framework seems to not be taking into account that if you say in a module:
all:
is_secure: off
you clearly want the framework to not check for any credential at all.
I really don’t know, in the meantime people we’ll have to use your fix.
Keep working and all the best to you.


March 17, 2009

in my case, what i’ve done it is to redefine the method hasCredentials in the myUser class to this:

class myUser extends sfGuardSecurityUser
{
public function hasCredential($credentials, $useAnd = true)
{
if ($this->getGuardUser() && $this->getGuardUser()->getIsSuperAdmin())
{
return true;
}
// método redefinido para o original da sfBasicSecurityUser
if (!is_array($credentials))
{
return in_array($credentials, $this->credentials);
}

// now we assume that $credentials is an array
$test = false;

foreach ($credentials as $credential)
{
// recursively check the credential with a switched AND/OR mode
$test = $this->hasCredential($credential, $useAnd ? false : true);

if ($useAnd)
{
$test = $test ? false : true;
}

if ($test) // either passed one in OR mode or failed one in AND mode
{
break; // the matter is settled
}
}

if ($useAnd) // in AND mode we succeed if $test is false
{
$test = $test ? false : true;
}

return $test;
}
}

the problem with the method hasCredentials from the sfGuardPlugin is that it forces you to have an object sfGuardUser, which only happens when you login.


March 23, 2009
jrh

getGuardUser() instanceof sfGuardUser && $this->getGuardUser()->getIsSuperAdmin())
{
return true;
}

return sfBasicSecurityUser::hasCredential($credential, $useAnd = true);
}
}


April 30, 2009
jrh

return sfBasicSecurityUser::hasCredential($credential, $useAnd = true); is wrong

the correct answer is

return sfBasicSecurityUser::hasCredential($credential, $useAnd);


June 22, 2009
Sebastian

Hello to all!!!

I am new as developer in symfony.

I do not have a lot of experience but i think the sfGuardPlugin has an error in the hasCredential method. to solve this error I think the best way is to redefine this method like this:

class myUser extends sfGuardSecurityUser
{
public function hasCredential($credential, $useAnd = true)
{
if (count($credential) == 0)
return true;
else
return parent::hasCredential($credential,$useAnd);
}
}

the error is that sfGuardSecurityUser do not verify if $credentia is empty.

Regards!

Sebastian


October 21, 2009
jukea

hey look, I filed a ticket around the same time you notices that, and it has been fixed in february

http://trac.symfony-project.org/ticket/5582


January 7, 2010
Winzter143

H! to all,

I reading the symfony docs but i cant get what $credential parameter is, in the hasCredential function. Is the $credential parameter is an Object, String or what?

Im newbie to this task..

Thank a lot for your reply.