diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ef7c973a2..41e8608d1 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -51,9 +51,8 @@ jobs: with: # Should be the higest supported version, so we can use the newest tools php-version: '8.3' - tools: composer, composer-require-checker, composer-unused, phpcs, psalm - # optional performance gain for psalm: opcache - extensions: ctype, date, dom, fileinfo, filter, hash, intl, ldap, mbstring, opcache, openssl, pcre, posix, spl, xml + tools: composer, composer-require-checker, composer-unused, phpcs + extensions: ctype, date, dom, fileinfo, filter, hash, intl, ldap, mbstring, openssl, pcre, posix, spl, xml - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" @@ -85,27 +84,13 @@ jobs: - name: PHP Code Sniffer run: phpcs - - name: Psalm - continue-on-error: true - run: | - psalm -c psalm.xml \ - --show-info=true \ - --shepherd \ - --php-version=${{ steps.setup-php.outputs.php-version }} - - - name: Psalm (testsuite) + - name: PHPStan run: | - psalm -c psalm-dev.xml \ - --show-info=true \ - --shepherd \ - --php-version=${{ steps.setup-php.outputs.php-version }} + vendor/bin/phpstan analyze -c phpstan.neon --debug - - name: Psalter + - name: PHPStan (testsuite) run: | - psalm --alter \ - --issues=UnnecessaryVarAnnotation \ - --dry-run \ - --php-version=${{ steps.setup-php.outputs.php-version }} + vendor/bin/phpstan analyze -c phpstan-dev.neon --debug security: name: Security checks diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..40bb15e35 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,21 @@ +parameters: + ignoreErrors: + - + message: "#^Call to an undefined method SimpleSAML\\\\Module\\\\ldap\\\\ConnectorInterface\\:\\:escapeFilterValue\\(\\)\\.$#" + count: 1 + path: src/Auth/Process/AttributeAddFromLDAP.php + + - + message: "#^Call to an undefined method SimpleSAML\\\\Module\\\\ldap\\\\ConnectorInterface\\:\\:escapeFilterValue\\(\\)\\.$#" + count: 1 + path: src/Auth/Process/AttributeAddUsersGroups.php + + - + message: "#^Call to an undefined method Symfony\\\\Component\\\\Ldap\\\\Adapter\\\\ConnectionInterface\\:\\:getResource\\(\\)\\.$#" + count: 1 + path: src/Connector/ActiveDirectory.php + + - + message: "#^Constructor of class SimpleSAML\\\\Module\\\\ldap\\\\Connector\\\\Ldap has an unused parameter \\$extension\\.$#" + count: 1 + path: src/Connector/Ldap.php diff --git a/phpstan-dev.neon b/phpstan-dev.neon new file mode 100644 index 000000000..4d29b8b51 --- /dev/null +++ b/phpstan-dev.neon @@ -0,0 +1,4 @@ +parameters: + level: 9 + paths: + - tests diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..ab978218a --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 3 + paths: + - src +includes: + - phpstan-baseline.neon diff --git a/psalm-dev.xml b/psalm-dev.xml deleted file mode 100644 index 6116331c7..000000000 --- a/psalm-dev.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index f15eb44fa..000000000 --- a/psalm.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Auth/InvalidCredentialResult.php b/src/Auth/InvalidCredentialResult.php index 9f05f486b..83e5be90c 100644 --- a/src/Auth/InvalidCredentialResult.php +++ b/src/Auth/InvalidCredentialResult.php @@ -57,7 +57,7 @@ class InvalidCredentialResult /** * Map of keys to check the code against when using is* methods * - * @var array + * @var array> */ protected array $codeMap = [ self::KEY_INVALID_CREDENTIAL => [ @@ -155,7 +155,7 @@ public function getRawMessage(): string /** * Allows the default code mappings to be updated - * @param array $codes + * @param array $codes * @return void */ public function updateCodeMap(array $codes): void @@ -167,7 +167,7 @@ public function updateCodeMap(array $codes): void /** * Allows the default code mappings to be replaced * - * @param array $codes + * @param array $codes * @return void */ public function replaceCodeMap(array $codes): void diff --git a/src/Auth/Process/AttributeAddFromLDAP.php b/src/Auth/Process/AttributeAddFromLDAP.php index 3aac2d93f..57baa8e24 100644 --- a/src/Auth/Process/AttributeAddFromLDAP.php +++ b/src/Auth/Process/AttributeAddFromLDAP.php @@ -21,14 +21,14 @@ class AttributeAddFromLDAP extends BaseFilter /** * LDAP attributes to add to the request attributes * - * @var array + * @var string[] */ protected array $searchAttributes; /** * LDAP attributes to base64 encode * - * @var array + * @var string[] */ protected array $binaryAttributes; @@ -55,7 +55,7 @@ class AttributeAddFromLDAP extends BaseFilter /** * Initialize this filter. * - * @param array $config Configuration information about this filter. + * @param array $config Configuration information about this filter. * @param mixed $reserved For future use. */ public function __construct(array $config, $reserved) @@ -83,7 +83,7 @@ public function __construct(array $config, $reserved) /** * Add attributes from an LDAP server. * - * @param array &$state The current request + * @param array &$state The current request */ public function process(array &$state): void { @@ -148,7 +148,6 @@ public function process(array &$state): void $this->binaryAttributes, ); foreach ($binaries as $binary) { - /** @psalm-var array $attr */ $attr = $entry->getAttribute($binary); $tmp[$binary] = array_map('base64_encode', $attr); } diff --git a/src/Auth/Process/AttributeAddUsersGroups.php b/src/Auth/Process/AttributeAddUsersGroups.php index 9bcd5a30c..54597aad3 100644 --- a/src/Auth/Process/AttributeAddUsersGroups.php +++ b/src/Auth/Process/AttributeAddUsersGroups.php @@ -33,7 +33,7 @@ class AttributeAddUsersGroups extends BaseFilter /** * Initialize this filter. * - * @param array $config Configuration information about this filter. + * @param array $config Configuration information about this filter. * @param mixed $reserved For future use. */ public function __construct(array $config, $reserved) @@ -51,7 +51,7 @@ public function __construct(array $config, $reserved) * LDAP search filters to be added to the base filters for this authproc-filter. * It's an array of key => value pairs that will be translated to (key=value) in the ldap query. * - * @var array + * @var array */ protected array $additional_filters; @@ -63,7 +63,7 @@ public function __construct(array $config, $reserved) * are then added to the request attributes. * * @throws \SimpleSAML\Error\Exception - * @param array &$state + * @param array &$state */ public function process(array &$state): void { @@ -124,8 +124,8 @@ public function process(array &$state): void * get their group membership, recursively. * * @throws \SimpleSAML\Error\Exception - * @param array $attributes - * @return array + * @param array $attributes + * @return array */ protected function getGroups(array $attributes): array { @@ -291,13 +291,11 @@ protected function getGroups(array $attributes): array $groups = []; foreach ($entries as $entry) { if ($entry->hasAttribute($return_attribute)) { - /** @psalm-var array $values */ $values = $entry->getAttribute($return_attribute); $groups[] = array_pop($values); continue; } elseif ($entry->hasAttribute(strtolower($return_attribute))) { // Some backends return lowercase attributes - /** @psalm-var array $values */ $values = $entry->getAttribute(strtolower($return_attribute)); $groups[] = array_pop($values); continue; @@ -330,9 +328,9 @@ protected function getGroups(array $attributes): array * Avoids loops by only searching a DN once. Returns * the list of groups found. * - * @param array $memberOf - * @param array $options - * @return array + * @param array $memberOf + * @param array $options + * @return array */ protected function search(array $memberOf, array $options): array { diff --git a/src/Auth/Process/BaseFilter.php b/src/Auth/Process/BaseFilter.php index 45c012492..9fede589b 100644 --- a/src/Auth/Process/BaseFilter.php +++ b/src/Auth/Process/BaseFilter.php @@ -17,7 +17,11 @@ abstract class BaseFilter extends Auth\ProcessingFilter { - // TODO: Support ldap:LDAPMulti, if possible + /** + * TODO: Support ldap:LDAPMulti, if possible + * + * @var string[] + */ protected static array $ldapsources = ['ldap:Ldap', 'authX509:X509userCert']; /** @@ -25,14 +29,14 @@ abstract class BaseFilter extends Auth\ProcessingFilter * name. Used for abstraction / configuration of the LDAP * attribute names, which may change between dir service. * - * @var array + * @var array */ protected array $attribute_map; /** * The base DN of the LDAP connection. Used when searching the LDAP server. * - * @var array + * @var array */ protected array $searchBase; @@ -64,7 +68,7 @@ abstract class BaseFilter extends Auth\ProcessingFilter * List of LDAP object types, used to determine the type of * object that a DN references. * - * @var array + * @var array */ protected array $type_map; @@ -75,7 +79,7 @@ abstract class BaseFilter extends Auth\ProcessingFilter * instance/object and stores everything in class members. * * @throws \SimpleSAML\Error\Exception - * @param array &$config + * @param array &$config * @param mixed $reserved */ public function __construct(array &$config, $reserved) @@ -164,6 +168,7 @@ public function __construct(array &$config, $reserved) * Parse authsource config * * @param string $as The name of the authsource + * @return array */ private function parseAuthSourceConfig(string $as): array { diff --git a/src/Auth/Source/Ldap.php b/src/Auth/Source/Ldap.php index 10dd0f22f..2f840c0d6 100644 --- a/src/Auth/Source/Ldap.php +++ b/src/Auth/Source/Ldap.php @@ -49,8 +49,8 @@ class Ldap extends UserPassBase /** * Constructor for this authentication source. * - * @param array $info Information about this authentication source. - * @param array $config Configuration. + * @param array $info Information about this authentication source. + * @param array $config Configuration. */ public function __construct(array $info, array $config) { @@ -71,11 +71,15 @@ public function __construct(array $info, array $config) * * @param string $username The username the user wrote. * @param string $password The password the user wrote. - * @param array|null $sasl_args SASL options - * @return array Associative array with the users attributes. + * @param array $sasl_args SASL options + * @return array Associative array with the users attributes. */ - protected function loginSasl(string $username, #[\SensitiveParameter]string $password, array $sasl_args = []): array - { + protected function loginSasl( + string $username, + #[\SensitiveParameter] + string $password, + array $sasl_args = [], + ): array { if (preg_match('/^\s*$/', $password)) { // The empty string is considered an anonymous bind to Symfony throw new Error\Error('WRONGUSERPASS'); @@ -110,7 +114,7 @@ protected function loginSasl(string $username, #[\SensitiveParameter]string $pas Assert::nullOrNotWhitespaceOnly($searchUsername); $searchPassword = $this->ldapConfig->getOptionalString('search.password', null); - Assert::nullOrnotWhitespaceOnly($searchPassword); + Assert::nullOrNotWhitespaceOnly($searchPassword); try { $this->connector->bind($searchUsername, $searchPassword); @@ -164,7 +168,7 @@ protected function loginSasl(string $username, #[\SensitiveParameter]string $pas * * @param string $username The username the user wrote. * @param string $password The password the user wrote. - * @return array Associative array with the users attributes. + * @return array Associative array with the users attributes. */ protected function login(string $username, #[\SensitiveParameter]string $password): array { @@ -176,7 +180,7 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor * Attempt to find a user's attributes given its username. * * @param string $username The username who's attributes we want. - * @return array Associative array with the users attributes. + * @return array Associative array with the users attributes. */ public function getAttributes(string $username): array { @@ -184,7 +188,7 @@ public function getAttributes(string $username): array Assert::nullOrNotWhitespaceOnly($searchUsername); $searchPassword = $this->ldapConfig->getOptionalString('search.password', null); - Assert::nullOrnotWhitespaceOnly($searchPassword); + Assert::nullOrNotWhitespaceOnly($searchPassword); try { $this->connector->bind($searchUsername, $searchPassword); @@ -232,7 +236,7 @@ public function getAttributes(string $username): array /** * @param \Symfony\Component\Ldap\Entry $entry - * @return array + * @return array */ private function processAttributes(Entry $entry): array { diff --git a/src/Auth/Source/LdapMulti.php b/src/Auth/Source/LdapMulti.php index 830d7a404..e3aef0d7c 100644 --- a/src/Auth/Source/LdapMulti.php +++ b/src/Auth/Source/LdapMulti.php @@ -33,16 +33,22 @@ class LdapMulti extends UserPassOrgBase /** * An array with mappings for organization => authsource. + * + * @var array */ private array $mapping; /** * An array with descriptions for organizations. + * + * @var array */ private array $orgs; /** * An array of organization IDs to LDAP configuration objects. + * + * @var array */ private array $ldapOrgs; @@ -55,8 +61,8 @@ class LdapMulti extends UserPassOrgBase /** * Constructor for this authentication source. * - * @param array $info Information about this authentication source. - * @param array $config Configuration. + * @param array $info Information about this authentication source. + * @param array $config Configuration. */ public function __construct(array $info, array $config) { @@ -109,15 +115,15 @@ public function __construct(array $info, array $config) * * @param string $username The username the user wrote. * @param string $password The password the user wrote. - * @param string $organizaion The organization the user chose. - * @param array|null $sasl_args SASL options - * @return array Associative array with the users attributes. + * @param string $organization The organization the user chose. + * @param array $sasl_args SASL options + * @return array Associative array with the users attributes. */ protected function loginSasl( string $username, #[\SensitiveParameter]string $password, string $organization, - ?array $sasl_args = [], + array $sasl_args = [], ): array { if ($this->includeOrgInUsername) { $username = $username . '@' . $organization; @@ -134,10 +140,14 @@ protected function loginSasl( $ldap = new class (['AuthId' => $authsource], $sourceConfig->toArray()) extends Ldap { + /** + * @param array $sasl_args + * @return array + */ public function loginOverload( string $username, #[\SensitiveParameter]string $password, - ?array $sasl_args, + array $sasl_args, ): array { return $this->loginSasl($username, $password, $sasl_args); } @@ -146,23 +156,25 @@ public function loginOverload( return $ldap->loginOverload($username, $password, $sasl_args); } + /** * Attempt to log in using the given username and password. * * @param string $username The username the user wrote. * @param string $password The password the user wrote. - * @param string $organizaion The organization the user chose. - * @return array Associative array with the users attributes. + * @param string $organization The organization the user chose. + * @return array Associative array with the users attributes. */ protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array { return $this->loginSasl($username, $password, $organization); } + /** * Retrieve list of organizations. * - * @return array Associative array with the organizations. + * @return array Associative array with the organizations. */ protected function getOrganizations(): array { diff --git a/src/Connector/Ldap.php b/src/Connector/Ldap.php index c62de6092..d5938a7f2 100644 --- a/src/Connector/Ldap.php +++ b/src/Connector/Ldap.php @@ -44,7 +44,7 @@ class Ldap implements ConnectorInterface * @param int $version * @param string $extension * @param bool $debug - * @param array $options + * @param array $options */ public function __construct( string $connection_strings, diff --git a/src/ConnectorInterface.php b/src/ConnectorInterface.php index 63f265f61..4535ac117 100644 --- a/src/ConnectorInterface.php +++ b/src/ConnectorInterface.php @@ -64,9 +64,9 @@ public function whoami(): string; /** * Search the LDAP-directory for a specific object * - * @param array $searchBase + * @param string[] $searchBase * @param string $filter - * @param array $options + * @param array $options * @param boolean $allowMissing * @return \Symfony\Component\Ldap\Entry|null The result of the search or null if none found * @psalm-return ($allowMissing is true ? \Symfony\Component\Ldap\Entry|null : \Symfony\Component\Ldap\Entry) @@ -85,9 +85,9 @@ public function search( /** * Search the LDAP-directory for any object matching the search filter * - * @param array $searchBase + * @param string[] $searchBase * @param string $filter - * @param array $options + * @param array $options * @param boolean $allowMissing * @return \Symfony\Component\Ldap\Entry[] The result of the search *