Issues (3)

src/Auth/Source/Htpasswd.php (2 issues)

1
<?php
2
3
/**
4
 * Authentication source for Apache 'htpasswd' files.
5
 *
6
 * @package SimpleSAMLphp
7
 */
8
9
declare(strict_types=1);
10
11
namespace SimpleSAML\Module\authcrypt\Auth\Source;
12
13
use Exception;
14
use SimpleSAML\{Error, Logger, Utils};
15
use SimpleSAML\Module\core\Auth\UserPassBase;
16
use WhiteHat101\Crypt\APR1_MD5;
17
18
use function array_merge;
19
use function crypt;
20
use function explode;
21
use function file_get_contents;
22
use function trim;
23
24
class Htpasswd extends UserPassBase
25
{
26
    /**
27
     * Our users, stored in an array, where each value is "<username>:<passwordhash>".
28
     *
29
     * @var array<int, mixed>
30
     */
31
    private array $users;
32
33
    /**
34
     * An array containing static attributes for our users.
35
     *
36
     * @var array<string, mixed>
37
     */
38
    private array $attributes = [];
39
40
41
    /**
42
     * Constructor for this authentication source.
43
     *
44
     * @param array<string, mixed> $info Information about this authentication source.
45
     * @param array<string, mixed> $config Configuration.
46
     *
47
     * @throws \Exception if the htpasswd file is not readable or the static_attributes array is invalid.
48
     */
49
    public function __construct(array $info, array $config)
50
    {
51
        // Call the parent constructor first, as required by the interface
52
        parent::__construct($info, $config);
53
54
        $this->users = [];
55
56
        if (!$htpasswd = file_get_contents($config['htpasswd_file'])) {
57
            throw new Exception('Could not read ' . $config['htpasswd_file']);
58
        }
59
60
        $this->users = explode("\n", trim($htpasswd));
61
62
        try {
63
            $attrUtils = new Utils\Attributes();
64
            $this->attributes = $attrUtils->normalizeAttributesArray($config['static_attributes']);
65
        } catch (Exception $e) {
66
            throw new Exception('Invalid static_attributes in authentication source ' .
67
                $this->authId . ': ' . $e->getMessage());
68
        }
69
    }
70
71
72
    /**
73
     * Attempt to log in using the given username and password.
74
     *
75
     * On a successful login, this function should return the username as 'uid' attribute,
76
     * and merged attributes from the configuration file.
77
     * On failure, it should throw an exception. A \SimpleSAML\Error\Error('WRONGUSERPASS')
78
     * should be thrown in case of a wrong username OR a wrong password, to prevent the
79
     * enumeration of usernames.
80
     *
81
     * @param string $username The username the user wrote.
82
     * @param string $password The password the user wrote.
83
     *
84
     * @return array<string, mixed> Associative array with the users attributes.
85
     *
86
     * @throws \SimpleSAML\Error\Error if authentication fails.
87
     */
88
    protected function login(
89
        string $username,
90
        #[\SensitiveParameter]
91
        string $password,
92
    ): array {
93
        $cryptoUtils = new Utils\Crypto();
94
        foreach ($this->users as $userpass) {
95
            $matches = explode(':', $userpass, 2);
96
            if ($matches[0] == $username) {
97
                $crypted = $matches[1];
98
99
                // This is about the only attribute we can add
100
                $attributes = array_merge(['uid' => [$username]], $this->attributes);
101
102
                // Traditional crypt(3)
103
                if ($cryptoUtils->secureCompare($crypted, crypt($password, $crypted))) {
0 ignored issues
show
Deprecated Code introduced by
The function SimpleSAML\Utils\Crypto::secureCompare() has been deprecated: Use hash_equals instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

103
                if (/** @scrutinizer ignore-deprecated */ $cryptoUtils->secureCompare($crypted, crypt($password, $crypted))) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
104
                    Logger::debug('User ' . $username . ' authenticated successfully');
105
                    Logger::warning(
106
                        'CRYPT authentication is insecure. Please consider using something else.',
107
                    );
108
                    return $attributes;
109
                }
110
111
                // Apache's custom MD5
112
                if (APR1_MD5::check($password, $crypted)) {
113
                    Logger::debug('User ' . $username . ' authenticated successfully');
114
                    Logger::warning(
115
                        'APR1 authentication is insecure. Please consider using something else.',
116
                    );
117
                    return $attributes;
118
                }
119
120
                // PASSWORD_BCRYPT
121
                if ($cryptoUtils->pwValid($crypted, $password)) {
0 ignored issues
show
Deprecated Code introduced by
The function SimpleSAML\Utils\Crypto::pwValid() has been deprecated: Use Symfony NativePasswordHasher::verify instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

121
                if (/** @scrutinizer ignore-deprecated */ $cryptoUtils->pwValid($crypted, $password)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
122
                    Logger::debug('User ' . $username . ' authenticated successfully');
123
                    return $attributes;
124
                }
125
                throw new Error\Error('WRONGUSERPASS');
126
            }
127
        }
128
        throw new Error\Error('WRONGUSERPASS');
129
    }
130
}
131