diff --git a/plugins/password/drivers/modoboa.php b/plugins/password/drivers/modoboa.php index 5532a15b1a..c848e111bc 100644 --- a/plugins/password/drivers/modoboa.php +++ b/plugins/password/drivers/modoboa.php @@ -2,11 +2,14 @@ /** * Modoboa Password Driver + * Minor modification from 2.0, updated to use Modoboa v2 password endpoint. + * Payload uses form-encoded data: current password and new password. + * Endpoint: PUT /api/v2/accounts/{id}/password/ * - * Payload is json string containing username, oldPassword and newPassword - * Return value is a json string saying result: true if success. + * Return value is a status constant (PASSWORD_SUCCESS on success, + * PASSWORD_CONNECT_ERROR on failure). * - * @version 2.0 + * @version 2.1 * * @author stephane @actionweb.fr * @@ -25,9 +28,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see https://www.gnu.org/licenses/. * - * The driver need modoboa core 1.10.6 or later + * The driver needs Modoboa core 2.0.0 or later * - * You need to define theses variables in plugin/password/config.inc.php + * You need to define these variables in plugin/password/config.inc.php * * $config['password_driver'] = 'modoboa'; // use modoboa as driver * $config['password_modoboa_api_token'] = ''; // put token number from Modoboa server @@ -40,59 +43,75 @@ public function save($curpass, $passwd, $username) { // Init config access $rcmail = rcmail::get_instance(); - $token = $rcmail->config->get('password_modoboa_api_token'); + $token = $rcmail->config->get('password_modoboa_api_token'); $IMAPhost = $_SESSION['imap_host']; + // uncomment and add your url if you use a differente url for your modoboa instance and api: + //$IMAPhost = 'mymodoboa.somewhere.net'; + // Use v2 API: search user by username $client = password::get_http_client(); - $url = "https://{$IMAPhost}/api/v1/accounts/?search=" . urlencode($username); + $url = "https://{$IMAPhost}/api/v2/accounts/?search=" . urlencode($username); $options = [ 'http_errors' => true, 'headers' => [ - 'Authorization' => "Token {$token}", - 'Cache-Control' => 'no-cache', - 'Content-Type' => 'application/json', + 'Authorization' => "Token " . $token, + 'Accept' => 'application/json', ], ]; - // Call GET to fetch values from modoboa server + // Call GET to fetch user details try { $response = $client->get($url, $options); - $response = $response->getBody()->getContents(); + $responseBody = $response->getBody()->getContents(); } catch (\Exception $e) { rcube::raise_error("Password plugin: Error fetching {$url} : {$e->getMessage()}", true); return PASSWORD_CONNECT_ERROR; } // Decode json string - $decoded = json_decode($response); + $decoded = json_decode($responseBody); - if (!is_array($decoded)) { + if (!is_array($decoded) || empty($decoded)) { return PASSWORD_CONNECT_ERROR; } // Get user ID (pk) $userid = $decoded[0]->pk; - // Encode json with new password - $options['body'] = json_encode([ - 'username' => $decoded[0]->username, - 'mailbox' => $decoded[0]->mailbox, - 'role' => $decoded[0]->role, - 'password' => $passwd, // new password - ]); - - $url = "https://{$IMAPhost}/api/v1/accounts/{$userid}/"; + // Call v2 password endpoint with form-encoded data + $url2 = "https://{$IMAPhost}/api/v2/accounts/" . $userid . "/password/"; + $options2 = [ + 'http_errors' => true, + 'headers' => [ + 'Authorization' => "Token " . $token, + 'Accept' => 'application/json', + // Content-Type will be set automatically when using form_params + ], + 'form_params' => [ + 'password' => $curpass, // current password + 'new_password' => $passwd // new password + ], + ]; - // Call HTTP API Modoboa + // Execute password change try { - $response = $client->put($url, $options); - $response = $response->getBody()->getContents(); + $response2 = $client->put($url2, $options2); + $responseBody2 = $response2->getBody()->getContents(); + $httpCode = $response2->getStatusCode(); } catch (\Exception $e) { - rcube::raise_error("Password plugin: Error on {$url} : {$e->getMessage()}", true); + rcube::raise_error("Password plugin: Error on {$url2} : {$e->getMessage()}", true); return PASSWORD_CONNECT_ERROR; } - return PASSWORD_SUCCESS; + // Check for success + if ($httpCode >= 200 && $httpCode < 300) { + return PASSWORD_SUCCESS; + } + + // Log for debugging if needed + rcube::raise_error("Password plugin: Unexpected response from {$url2}. HTTP {$httpCode}. Response: {$responseBody2}", true); + return PASSWORD_CONNECT_ERROR; } } +?>