lucidprogrammer / yii2-simplesamlphp

SAML Service Provider(SP) for Yii2 using simplesamlphp (yii2 extension)
BSD 3-Clause "New" or "Revised" License
4 stars 5 forks source link

Error: Class samlsettings does not exist #1

Open mhoffmann75 opened 6 years ago

mhoffmann75 commented 6 years ago

After enabling extension to the user class its broken:

'user' => [
    'class' => 'lucidprogrammer\simplesamlphp\SamlUser',

I get the following error:

ReflectionException: Class samlsettings does not exist in /app/basic/vendor/yiisoft/yii2/di/Container.php:428
Stack trace:
#0 /app/basic/vendor/yiisoft/yii2/di/Container.php(428): ReflectionClass->__construct('samlsettings')
     * @return array the dependencies of the specified class.
     */
    protected function getDependencies($class)
    {
        if (isset($this->_reflections[$class])) {
            return [$this->_reflections[$class], $this->_dependencies[$class]];
        }

        $dependencies = [];
----->        $reflection = new ReflectionClass($class);

        $constructor = $reflection->getConstructor();
        if ($constructor !== null) {
            foreach ($constructor->getParameters() as $param) {
                if (version_compare(PHP_VERSION, '5.6.0', '>=') && $param->isVariadic()) {
                    break;
                } elseif ($param->isDefaultValueAvailable()) {
                    $dependencies[] = $param->getDefaultValue();
                } else {
#1 /app/basic/vendor/yiisoft/yii2/di/Container.php(364): yii\di\Container->getDependencies('samlsettings')
#2 /app/basic/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('samlsettings', Array, Array)
#3 /app/basic/vendor/lucidprogrammer/yii2-simplesamlphp/src/SamlUser.php(31): yii\di\Container->get('samlsettings')
    if(array_key_exists('idAttribute', $attributes)){
      $idAttribute = $attributes['idAttribute'];
      $mappings = (new ArrayObject($attributes))->getArrayCopy();
      unset($mappings['idAttribute']);
      $mappings = array_values($mappings);
    }
----->    Yii::$container->get('samlsettings')->idAttribute = $idAttribute;
    Yii::$container->get('samlsettings')->mappings = $mappings;

    parent::__construct();
  }
  /**
  * changing the loginUrl and identityClass

#4 [internal function]: lucidprogrammer\simplesamlphp\SamlUser->__construct(Array)
#5 /app/basic/vendor/yiisoft/yii2/di/Container.php(383): ReflectionClass->newInstanceArgs(Array)
#6 /app/basic/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('lucidprogrammer...', Array, Array)
#7 /app/basic/vendor/yiisoft/yii2/BaseYii.php(349): yii\di\Container->get('lucidprogrammer...', Array, Array)
#8 /app/basic/vendor/yiisoft/yii2/di/ServiceLocator.php(137): yii\BaseYii::createObject(Array)
#9 /app/basic/vendor/yiisoft/yii2/base/Module.php(742): yii\di\ServiceLocator->get('user', false)
#10 /app/basic/vendor/yiisoft/yii2-debug/panels/UserPanel.php(109): yii\base\Module->get('user', false)
#11 /app/basic/vendor/yiisoft/yii2-debug/panels/UserPanel.php(296): yii\debug\panels\UserPanel->getUser()
#12 /app/basic/vendor/yiisoft/yii2-debug/panels/UserPanel.php(80): yii\debug\panels\UserPanel->isEnabled()
#13 /app/basic/vendor/yiisoft/yii2/base/BaseObject.php(109): yii\debug\panels\UserPanel->init()
#14 [internal function]: yii\base\BaseObject->__construct(Array)
#15 /app/basic/vendor/yiisoft/yii2/di/Container.php(383): ReflectionClass->newInstanceArgs(Array)
#16 /app/basic/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('yii\\debug\\panel...', Array, Array)
#17 /app/basic/vendor/yiisoft/yii2/BaseYii.php(349): yii\di\Container->get('yii\\debug\\panel...', Array, Array)
#18 /app/basic/vendor/yiisoft/yii2-debug/Module.php(177): yii\BaseYii::createObject(Array)
#19 /app/basic/vendor/yiisoft/yii2-debug/Module.php(149): yii\debug\Module->initPanels()
#20 /app/basic/vendor/yiisoft/yii2/base/BaseObject.php(109): yii\debug\Module->init()
#21 /app/basic/vendor/yiisoft/yii2/base/Module.php(158): yii\base\BaseObject->__construct(Array)
#22 [internal function]: yii\base\Module->__construct('debug', Object(yii\web\Application), Array)
#23 /app/basic/vendor/yiisoft/yii2/di/Container.php(383): ReflectionClass->newInstanceArgs(Array)
#24 /app/basic/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('yii\\debug\\Modul...', Array, Array)
#25 /app/basic/vendor/yiisoft/yii2/BaseYii.php(349): yii\di\Container->get('yii\\debug\\Modul...', Array, Array)
#26 /app/basic/vendor/yiisoft/yii2/base/Module.php(427): yii\BaseYii::createObject(Array, Array)
#27 /app/basic/vendor/yiisoft/yii2/base/Application.php(315): yii\base\Module->getModule('debug')
#28 /app/basic/vendor/yiisoft/yii2/web/Application.php(69): yii\base\Application->bootstrap()
#29 /app/basic/vendor/yiisoft/yii2/base/Application.php(273): yii\web\Application->bootstrap()
#30 /app/basic/vendor/yiisoft/yii2/base/BaseObject.php(109): yii\base\Application->init()
#31 /app/basic/vendor/yiisoft/yii2/base/Application.php(206): yii\base\BaseObject->__construct(Array)
#32 /app/basic/web/index.php(12): yii\base\Application->__construct(Array)
#33 {main}

So what am i missing here?

yii2 Version: 2.0.15.1 php 7.2.8

mhoffmann75 commented 6 years ago

It has something todo with the code in BootstrapClass.php never running as it should:

commenting out # $app->on(Application::EVENT_BEFORE_REQUEST, function () { thus running the initialisation directly solved the error. However still it does not work properly:

Second: BaseObject.php workaround for php 7.2 does not work correctly, had to change \yii\base\BaseObject in your BaseObject.php.

Any ideas how to get this properly running with latest php and latest yii2 ?

Forgot to mention: Login via /saml works of course.

lucidprogrammer commented 6 years ago

Forgot to mention: Login via /saml works of course.

@mhoffmann75 thats the only intended purpose of the component.

You will have the data(whatever data received by the SAML payload) now in the call back, you can do whatever is your logic to integrate. For example, you may use in session, drive your UI logic etc.

public function actionIndex()
{
  var_dump(Yii::$app->user);
}

If you don't see anything there, you need to see if the IDP is sending you anything. Use a SAML plugin on your browser and check the actual incoming payload.

If needed change the id attribute as in the README.

mhoffmann75 commented 6 years ago

The strange thing is that working with /saml alone (test mode of simplesamlphp) returns all attributes from identity provider as expected. As said before, Yii::$app->user dumped from site/index does NOT contain any of these attributes or id.

However if if add this dumper in your _SamlController.php right before the $this->goBack(); its attributes and id are all visible in Yii::$app->user. So it seems as if the redirect to site/index starts a new session killing all settings. But i don't get why. Although the redirect is wrong as it should redirect to to the about page where i came from originally.

Any idea?

lucidprogrammer commented 6 years ago

See in the Readme - Step 2. You need to know which attribute you should assign to yii. You need to specifically assign the attribute.

mhoffmann75 commented 6 years ago

Seems i had some quirks in RBAC logic.

However your code does not work out of the box, as the bootstrap code which should init everything is never executed because of the EVENT_BEFORE_REQUEST.

After changing your BootstrapClass.php as follows the Error "ReflectionException: Class samlsettings does not exist in ..." went away:

class BootstrapClass implements BootstrapInterface
{
    public function bootstrap($app)
    {
//        $app->on(Application::EVENT_BEFORE_REQUEST, function () {
            //creating a controller for the login route
            Yii::$app->controllerMap['_saml'] = '\lucidprogrammer\simplesamlphp\_SamlController';
            //a globally accessible instance of saml
            Yii::$container->set('saml',new Saml());
            Yii::$container->set('samlsettings',new SamlSettings());
            // TODO possibly check if the user has enabled /saml alias.
//        });
    }
}

Maybe you have an idea why this not working or you might check your code?