neos / flow-development-collection

The unified repository containing the Flow core packages, used for Flow development.
https://flow.neos.io/
MIT License
137 stars 188 forks source link

Authentication fails with custom Account object implementation #2737

Open davidspiola opened 2 years ago

davidspiola commented 2 years ago

Description

If you use an extended custom \Neos\Flow\Security\Account object for authentication a Doctrine exception occurs in \Neos\Party\Domain\Repository\PartyRepository::findOneHavingAccount. Once I cast my JwtAccount to an Account object, the code works as expected. In my case, the custom Account object is of type \RFY\JWT\Security\JwtAccount which is part of the https://github.com/rfyio/JWT package. This worked as expected in previous flow verions

Steps to Reproduce

  1. Create an extended custom Account class (or use the JWT Package) and use it for authentication in a provider/token -> will fail
  2. Cast the JwtAccount object to an Account object and retry auth -> will work

Due to the lag of more profound knowledge, I used this method for casting

/**
     * Class casting
     *
     * @param string|object $destination
     * @param object $sourceObject
     * @return object
     */
    function cast($destination, $sourceObject)
    {
        if (is_string($destination)) {
            $destination = new $destination();
        }
        $sourceReflection = new \ReflectionObject($sourceObject);
        $destinationReflection = new \ReflectionObject($destination);
        $sourceProperties = $sourceReflection->getProperties();
        foreach ($sourceProperties as $sourceProperty) {
            $sourceProperty->setAccessible(true);
            $name = $sourceProperty->getName();
            $value = $sourceProperty->getValue($sourceObject);
            if ($destinationReflection->hasProperty($name)) {
                $propDest = $destinationReflection->getProperty($name);
                $propDest->setAccessible(true);
                $propDest->setValue($destination,$value);
            } else {
                $destination->$name = $value;
            }
        }
        return $destination;
    }

Expected behavior

Authentication works, and no Doctrine exception will be thrown without casting the object

Actual behavior

A doctrine exception occurs, and authentication fails.

Affected Versions

neos/flow 7.3.1

davidspiola commented 2 years ago

Exception


Object of class RFY\JWT\Security\JwtAccount could not be converted to string

119 Doctrine\DBAL\DBALException::wrapException(Doctrine\DBAL\Driver\PDO\MySQL\Driver, Error, "An exception occurred while executing 'SELECT n0_.…curity\JwtAccount could not be converted to string")
118 Doctrine\DBAL\DBALException::driverExceptionDuringQuery(Doctrine\DBAL\Driver\PDO\MySQL\Driver, Error, "SELECT n0_.persistence_object_identifier AS persis…ier AND n3_.flow_security_account IN (?))) LIMIT 1", array|1|)
117 Doctrine\DBAL\Connection::handleExceptionDuringQuery(Error, "SELECT n0_.persistence_object_identifier AS persis…ier AND n3_.flow_security_account IN (?))) LIMIT 1", array|1|, array|1|)
116 Doctrine\DBAL\Connection::executeQuery("SELECT n0_.persistence_object_identifier AS persis…ier AND n3_.flow_security_account IN (?))) LIMIT 1", array|1|, array|1|, NULL)
115 Doctrine\ORM\Query\Exec\SingleSelectExecutor::execute(Doctrine\DBAL\Connection, array|1|, array|1|)
114 Doctrine\ORM\Query::_doExecute()
113 Doctrine\ORM\AbstractQuery::executeIgnoreQueryCache(NULL, 1)
112 Doctrine\ORM\AbstractQuery::execute(NULL, 1)
111 Doctrine\ORM\AbstractQuery::getResult()
110 Neos\Flow\Persistence\Doctrine\Query_Original::getResult()
109 Neos\Flow\Persistence\Doctrine\QueryResult_Original::getFirst()
108 Neos\Party\Domain\Repository\PartyRepository_Original::findOneHavingAccount(RFY\JWT\Security\JwtAccount)
107 Neos\Party\Domain\Service\PartyService_Original::getAssignedPartyOfAccount(RFY\JWT\Security\JwtAccount)
106 Neos\Flow\ObjectManagement\DependencyInjection\DependencyProxy::__call("getAssignedPartyOfAccount", array|1|)
105 Neos\Neos\Domain\Service\UserService_Original::getNeosUserForAccount(RFY\JWT\Security\JwtAccount)
104 Neos\Neos\Domain\Service\UserService_Original::Neos\Neos\Domain\Service\{closure}(NULL, RFY\JWT\Security\Authentication\Token\JwtToken)
103 array_reduce(array|1|, Closure, NULL)
102 Neos\Neos\Domain\Service\UserService_Original::getCurrentUser()
101 Neos\Flow\ObjectManagement\DependencyInjection\DependencyProxy::__call("getCurrentUser", array|0|)
100 Neos\Neos\Service\UserService_Original::getBackendUser()
99 Neos\Utility\ObjectAccess::getPropertyInternal(Neos\Neos\Service\UserService, "backendUser", false, true)
98 Neos\Utility\ObjectAccess::getPropertyPath(Neos\Neos\Service\UserService, "backendUser")
97 Neos\Flow\Aop\Pointcut\RuntimeExpressionEvaluator::{closure}(Neos\Flow\Aop\JoinPoint, Neos\Flow\ObjectManagement\ObjectManager)
96 Closure::__invoke(Neos\Flow\Aop\JoinPoint, Neos\Flow\ObjectManagement\ObjectManager)