Skip to content

Commit b4b1fbd

Browse files
manu0401tvdijen
andauthored
Add support for SASL bind (#62)
* Add support for SASL bind We introduce a ldap_sasl() method in Ldap and LdapMulti with an optionnal array of SASL options. A module that subclasses Ldap or Ldapmulti can use it instead of simple login(). This requires SASL bind support in Symfony, which has been merged in the 7.3 branch. SimpleSAMLphp uses Symfony 7.2. How should this ne handled? I can backport the patches for Symfony 7.2, but do we have a way to fold them in the simpleSAMLphp package? * Check for Symfony's saslBind and whoami method presence * Fix QA-issues * Rename method * Rename method * Fix QA * Remove whitespace from end of line * Remove whitespace from end of line * Fix long line * Fix: Allow optional sasl_args parameter --------- Co-authored-by: Tim van Dijen <[email protected]>
1 parent 14c06d3 commit b4b1fbd

File tree

4 files changed

+132
-10
lines changed

4 files changed

+132
-10
lines changed

src/Auth/Source/Ldap.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ public function __construct(array $info, array $config)
6767

6868

6969
/**
70-
* Attempt to log in using the given username and password.
70+
* Attempt to log in using SASL and the given username and password.
7171
*
7272
* @param string $username The username the user wrote.
7373
* @param string $password The password the user wrote.
74+
* @param array|null $sasl_args SASL options
7475
* @return array Associative array with the users attributes.
7576
*/
76-
protected function login(string $username, #[\SensitiveParameter]string $password): array
77+
protected function loginSasl(string $username, #[\SensitiveParameter]string $password, array $sasl_args = []): array
7778
{
7879
if (preg_match('/^\s*$/', $password)) {
7980
// The empty string is considered an anonymous bind to Symfony
@@ -128,7 +129,22 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor
128129
}
129130

130131
/* Verify the credentials */
131-
$this->connector->bind($dn, $password);
132+
if (empty($sasl_args)) {
133+
Assert::isArray($sasl_args);
134+
135+
$this->connector->saslBind(
136+
$dn,
137+
$password,
138+
$sasl_args['mech'],
139+
$sasl_args['realm'],
140+
$sasl_args['authc_id'],
141+
$sasl_args['authz_id'],
142+
$sasl_args['props'],
143+
);
144+
$dn = $this->connector->whoami();
145+
} else {
146+
$this->connector->bind($dn, $password);
147+
}
132148

133149
/* If the credentials were correct, rebind using a privileged account to read attributes */
134150
$readUsername = $this->ldapConfig->getOptionalString('priv.username', null);
@@ -145,6 +161,18 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor
145161
return $this->processAttributes(/** @scrutinizer-ignore-type */$entry);
146162
}
147163

164+
/**
165+
* Attempt to log in using the given username and password.
166+
*
167+
* @param string $username The username the user wrote.
168+
* @param string $password The password the user wrote.
169+
* @return array Associative array with the users attributes.
170+
*/
171+
protected function login(string $username, #[\SensitiveParameter]string $password): array
172+
{
173+
return $this->loginSasl($username, $password);
174+
}
175+
148176

149177
/**
150178
* Attempt to find a user's attributes given its username.

src/Auth/Source/LdapMulti.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,20 @@ public function __construct(array $info, array $config)
105105

106106

107107
/**
108-
* Attempt to log in using the given username and password.
108+
* Attempt to log in using SASL and the given username and password.
109109
*
110110
* @param string $username The username the user wrote.
111111
* @param string $password The password the user wrote.
112+
* @param string $organizaion The organization the user chose.
113+
* @param array|null $sasl_args SASL options
112114
* @return array Associative array with the users attributes.
113115
*/
114-
protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array
115-
{
116+
protected function loginSasl(
117+
string $username,
118+
#[\SensitiveParameter]string $password,
119+
string $organization,
120+
?array $sasl_args,
121+
): array {
116122
if ($this->includeOrgInUsername) {
117123
$username = $username . '@' . $organization;
118124
}
@@ -128,15 +134,30 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor
128134

129135
$ldap = new class (['AuthId' => $authsource], $sourceConfig->toArray()) extends Ldap
130136
{
131-
public function loginOverload(string $username, #[\SensitiveParameter]string $password): array
132-
{
133-
return $this->login($username, $password);
137+
public function loginOverload(
138+
string $username,
139+
#[\SensitiveParameter]string $password,
140+
?array $sasl_args,
141+
): array {
142+
return $this->loginSasl($username, $password, $sasl_args);
134143
}
135144
};
136145

137-
return $ldap->loginOverload($username, $password);
146+
return $ldap->loginOverload($username, $password, $sasl_args);
138147
}
139148

149+
/**
150+
* Attempt to log in using the given username and password.
151+
*
152+
* @param string $username The username the user wrote.
153+
* @param string $password The password the user wrote.
154+
* @param string $organizaion The organization the user chose.
155+
* @return array Associative array with the users attributes.
156+
*/
157+
protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array
158+
{
159+
return $this->loginSasl($username, $password, $organization);
160+
}
140161

141162
/**
142163
* Retrieve list of organizations.

src/Connector/Ldap.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,46 @@ public function bind(?string $username, #[\SensitiveParameter]?string $password)
109109
}
110110
}
111111

112+
/**
113+
* @inheritDoc
114+
*/
115+
public function saslBind(
116+
?string $username,
117+
#[\SensitiveParameter]?string $password,
118+
?string $mech,
119+
?string $realm,
120+
?string $authcId,
121+
?string $authzId,
122+
?string $props,
123+
): void {
124+
if (!method_exists($this->connection, 'saslBind')) {
125+
throw new Error\Error("SASL not implemented");
126+
}
127+
128+
try {
129+
$this->connection->saslBind($username, strval($password), $mech, $realm, $authcId, $authzId, $props);
130+
} catch (InvalidCredentialsException $e) {
131+
throw new Error\Error($this->resolveBindError($e));
132+
}
133+
134+
if ($username === null) {
135+
Logger::debug("LDAP bind(): Anonymous bind succesful.");
136+
} else {
137+
Logger::debug(sprintf("LDAP bind(): Bind successful for DN '%s'.", $username));
138+
}
139+
}
140+
141+
/**
142+
* @inheritDoc
143+
*/
144+
public function whoami(): string
145+
{
146+
if (!method_exists($this->connection, 'whoami')) {
147+
throw new Error\Error("SASL not implemented");
148+
}
149+
150+
return $this->connection->whoami();
151+
}
112152

113153
/**
114154
* @inheritDoc

src/ConnectorInterface.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,39 @@ public function bind(
2828
): void;
2929

3030

31+
/**
32+
* Bind to an LDAP-server using SASL
33+
*
34+
* @param string|null $username
35+
* @param string|null $password Null for passwordless logon
36+
* @param string|null $mech
37+
* @param string|null $realm
38+
* @param string|null $authcId
39+
* @param string|null $authzId
40+
* @param string|null $props
41+
* @return void
42+
*
43+
* @throws \SimpleSAML\Error\Exception if none of the LDAP-servers could be contacted
44+
*/
45+
public function saslBind(
46+
?string $username,
47+
?string $password,
48+
?string $mech,
49+
?string $realm,
50+
?string $authcId,
51+
?string $authzId,
52+
?string $props,
53+
): void;
54+
55+
56+
/**
57+
* Return the authenticated DN
58+
*
59+
* @return string
60+
*/
61+
public function whoami(): string;
62+
63+
3164
/**
3265
* Search the LDAP-directory for a specific object
3366
*

0 commit comments

Comments
 (0)