Skip to content

Commit

Permalink
Add support for SASL bind
Browse files Browse the repository at this point in the history
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?
  • Loading branch information
manu0401 committed Oct 30, 2024
1 parent 14c06d3 commit 7462d23
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
26 changes: 23 additions & 3 deletions src/Auth/Source/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,14 @@ public function __construct(array $info, array $config)


/**
* Attempt to log in using the given username and password.
* Attempt to log in using SASL and the given username and password.
*
* @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.
*/
protected function login(string $username, #[\SensitiveParameter]string $password): array
protected function login_sasl(string $username, #[\SensitiveParameter]string $password, ?array $sasl_args): array
{
if (preg_match('/^\s*$/', $password)) {
// The empty string is considered an anonymous bind to Symfony
Expand Down Expand Up @@ -128,7 +129,14 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor
}

/* Verify the credentials */
$this->connector->bind($dn, $password);
if (isset($sasl_args)) {
Assert::isArray($sasl_args);

$this->connector->saslBind($dn, $password, $sasl_args['mech'], $sasl_args['realm'], $sasl_args['authc_id'], $sasl_args['authz_id'], $sasl_args['props']);
$dn = $this->connector->whoami();
} else {
$this->connector->bind($dn, $password);
}

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

/**
* 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.
* @return array Associative array with the users attributes.
*/
protected function login(string $username, #[\SensitiveParameter]string $password): array
{
return $this->login_sasl($username, $password);
}


/**
* Attempt to find a user's attributes given its username.
Expand Down
24 changes: 19 additions & 5 deletions src/Auth/Source/LdapMulti.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,15 @@ public function __construct(array $info, array $config)


/**
* Attempt to log in using the given username and password.
* Attempt to log in using SASL and 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.
* @param array|null $sasl_args SASL options
* @return array Associative array with the users attributes.
*/
protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array
protected function login_sasl(string $username, #[\SensitiveParameter]string $password, string $organization, ?array $sasl_args): array
{
if ($this->includeOrgInUsername) {
$username = $username . '@' . $organization;
Expand All @@ -128,15 +130,27 @@ protected function login(string $username, #[\SensitiveParameter]string $passwor

$ldap = new class (['AuthId' => $authsource], $sourceConfig->toArray()) extends Ldap
{
public function loginOverload(string $username, #[\SensitiveParameter]string $password): array
public function loginOverload(string $username, #[\SensitiveParameter]string $password, ?array $sasl_args): array
{
return $this->login($username, $password);
return $this->login_sasl($username, $password, $sasl_args);
}
};

return $ldap->loginOverload($username, $password);
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.
*/
protected function login(string $username, #[\SensitiveParameter]string $password, string $organization): array
{
return $this->login_sasl($username, $password, $organization);
}

/**
* Retrieve list of organizations.
Expand Down
26 changes: 26 additions & 0 deletions src/Connector/Ldap.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,32 @@ public function bind(?string $username, #[\SensitiveParameter]?string $password)
}
}

/**
* @inheritDoc
*/
public function saslBind(?string $username, #[\SensitiveParameter]?string $password, ?string $mech, ?string $realm, ?string $authcId, ?string $authzId, ?string $props): void

{
try {
$this->connection->saslBind($username, strval($password), $mech, $realm, $authcId, $authzId, $props);
} catch (InvalidCredentialsException $e) {
throw new Error\Error($this->resolveBindError($e));
}

if ($username === null) {
Logger::debug("LDAP bind(): Anonymous bind succesful.");
} else {
Logger::debug(sprintf("LDAP bind(): Bind successful for DN '%s'.", $username));
}
}

/**
* @inheritDoc
*/
public function whoami(): string
{
return $this->connection->whoami();
}

/**
* @inheritDoc
Expand Down
33 changes: 33 additions & 0 deletions src/ConnectorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,39 @@ public function bind(
): void;


/**
* Bind to an LDAP-server using SASL
*
* @param string|null $username
* @param string|null $password Null for passwordless logon
* @param string|null $mech
* @param string|null $realm
* @param string|null $authcId
* @param string|null $authzId
* @param string|null $props
* @return void
*
* @throws \SimpleSAML\Error\Exception if none of the LDAP-servers could be contacted
*/
public function saslBind(
?string $username,
?string $password,
?string $mech,
?string $realm,
?string $authcId,
?string $authzId,
?string $props
): void;


/**
* Return the authenticated DN
*
* @return string
*/
public function whoami(): string;


/**
* Search the LDAP-directory for a specific object
*
Expand Down

0 comments on commit 7462d23

Please sign in to comment.