LdapMulti::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 41
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 41
rs 9.504
c 0
b 0
f 0
eloc 26
nc 3
nop 2
1
<?php
2
3
/**
4
 * LDAP authentication source.
5
 *
6
 * See the ldap-entry in config-templates/authsources.php for information about
7
 * configuration of this authentication source.
8
 *
9
 * This class is based on www/auth/login.php.
10
 *
11
 * @package simplesamlphp/simplesamlphp-module-ldap
12
 */
13
14
declare(strict_types=1);
15
16
namespace SimpleSAML\Module\ldap\Auth\Source;
17
18
use SimpleSAML\Assert\Assert;
19
use SimpleSAML\Auth;
20
use SimpleSAML\Configuration;
21
use SimpleSAML\Error;
22
use SimpleSAML\Module\core\Auth\UserPassOrgBase;
23
24
use function array_key_exists;
25
use function var_export;
26
27
class LdapMulti extends UserPassOrgBase
28
{
29
    /**
30
     * An LDAP configuration object.
31
     */
32
    private Configuration $ldapConfig;
33
34
    /**
35
     * An array with mappings for organization => authsource.
36
     *
37
     * @var array<mixed>
38
     */
39
    private array $mapping;
40
41
    /**
42
     * An array with descriptions for organizations.
43
     *
44
     * @var array<mixed>
45
     */
46
    private array $orgs;
47
48
    /**
49
     * An array of organization IDs to LDAP configuration objects.
50
     *
51
     * @var array<mixed>
52
     */
53
    private array $ldapOrgs;
54
55
    /**
56
     * Whether we should include the organization as part of the username.
57
     */
58
    private bool $includeOrgInUsername;
59
60
61
    /**
62
     * Constructor for this authentication source.
63
     *
64
     * @param array<mixed> $info  Information about this authentication source.
65
     * @param array<mixed> $config  Configuration.
66
     */
67
    public function __construct(array $info, array $config)
68
    {
69
        // Call the parent constructor first, as required by the interface
70
        parent::__construct($info, $config);
71
72
        $this->ldapConfig = Configuration::loadFromArray(
73
            $config,
74
            'authsources[' . var_export($this->authId, true) . ']',
75
        );
76
77
        $usernameOrgMethod = $this->ldapConfig->getValueValidate(
78
            'username_organization_method',
79
            ['none', 'allow', 'force'],
80
        );
81
        $this->setUsernameOrgMethod($usernameOrgMethod);
82
83
        $this->includeOrgInUsername = $this->ldapConfig->getOptionalBoolean(
84
            'include_organization_in_username',
85
            false,
86
        );
87
88
        $this->mapping = $this->ldapConfig->getArray('mapping');
89
        Assert::notEmpty($this->mapping);
90
91
        $organizations = array_keys($this->mapping);
92
        $authsources = Configuration::getConfig('authsources.php');
93
94
        foreach ($organizations as $organization) {
95
            Assert::keyExists($this->mapping[$organization], 'authsource');
96
            $authsource = $this->mapping[$organization]['authsource'];
97
            Assert::notNull(Auth\Source::getById($authsource, Ldap::class));
98
99
            if (array_key_exists('description', $this->mapping[$organization])) {
100
                $this->orgs[$organization] = $this->mapping[$organization]['description'];
101
            } else {
102
                $this->orgs[$organization] = $organization;
103
            }
104
105
            $this->ldapOrgs[$organization] = Configuration::loadFromArray(
106
                $authsources->getValue($authsource),
107
                'authsources[' . var_export($this->authId, true) . '][' . var_export($organization, true) . ']',
108
            );
109
        }
110
    }
111
112
113
    /**
114
     * Attempt to log in using SASL and the given username and password.
115
     *
116
     * @param string $username  The username the user wrote.
117
     * @param string $password  The password the user wrote.
118
     * @param string $organization  The organization the user chose.
119
     * @param array<mixed> $sasl_args SASL options
120
     * @return array<mixed> Associative array with the users attributes.
121
     */
122
    protected function loginSasl(
123
        string $username,
124
        #[\SensitiveParameter]string $password,
125
        string $organization,
126
        array $sasl_args = [],
127
    ): array {
128
        if ($this->includeOrgInUsername) {
129
            $username = $username . '@' . $organization;
130
        }
131
132
        $authsource = $this->mapping[$organization]['authsource'];
133
134
        if (!array_key_exists($organization, $this->ldapOrgs)) {
135
            // The organization is unknown to us.
136
            throw new Error\Error('WRONGUSERPASS');
137
        }
138
139
        $sourceConfig = $this->ldapOrgs[$organization];
140
141
        $ldap = new class (['AuthId' => $authsource], $sourceConfig->toArray()) extends Ldap
142
        {
143
            /**
144
             * @param array<mixed> $sasl_args
145
             * @return array<mixed>
146
             */
147
            public function loginOverload(
148
                string $username,
149
                #[\SensitiveParameter]string $password,
150
                array $sasl_args,
151
            ): array {
152
                return $this->loginSasl($username, $password, $sasl_args);
153
            }
154
        };
155
156
        return $ldap->loginOverload($username, $password, $sasl_args);
157
    }
158
159
160
    /**
161
     * Attempt to log in using the given username and password.
162
     *
163
     * @param string $username  The username the user wrote.
164
     * @param string $password  The password the user wrote.
165
     * @param string $organization  The organization the user chose.
166
     * @return array<mixed> Associative array with the users attributes.
167
     */
168
    protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array
169
    {
170
        return $this->loginSasl($username, $password, $organization);
171
    }
172
173
174
    /**
175
     * Retrieve list of organizations.
176
     *
177
     * @return array<mixed> Associative array with the organizations.
178
     */
179
    protected function getOrganizations(): array
180
    {
181
        return $this->orgs;
182
    }
183
}
184