From 1b8ca08e5b042035b096c61d094fab0157941f17 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 06 Aug 2015 07:23:50 -0400 Subject: [PATCH] Added GSSAPI/Kerberos authentication plugin - krb_authentication --- program/lib/Roundcube/rcube_imap_generic.php | 72 +++++++++++++++++++++++++++++++++--- 1 files changed, 66 insertions(+), 6 deletions(-) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 498793e..daf0abe 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -552,14 +552,12 @@ $this->putLine($reply, true, true); $line = trim($this->readReply()); - if ($line[0] == '+') { - $challenge = substr($line, 2); - } - else { + if ($line[0] != '+') { return $this->parseResult($line); } // check response + $challenge = substr($line, 2); $challenge = base64_decode($challenge); if (strpos($challenge, 'rspauth=') === false) { $this->setError(self::ERROR_BAD, @@ -571,6 +569,66 @@ } $line = $this->readReply(); + $result = $this->parseResult($line); + } + elseif ($type == 'GSSAPI') { + if (!extension_loaded('krb5')) { + $this->setError(self::ERROR_BYE, + "The krb5 extension is required for GSSAPI authentication"); + return self::ERROR_BAD; + } + + if (empty($this->prefs['gssapi_cn'])) { + $this->setError(self::ERROR_BYE, + "The gssapi_cn parameter is required for GSSAPI authentication"); + return self::ERROR_BAD; + } + + if (empty($this->prefs['gssapi_context'])) { + $this->setError(self::ERROR_BYE, + "The gssapi_context parameter is required for GSSAPI authentication"); + return self::ERROR_BAD; + } + + putenv('KRB5CCNAME=' . $this->prefs['gssapi_cn']); + + try { + $ccache = new KRB5CCache(); + $ccache->open($this->prefs['gssapi_cn']); + $gssapicontext = new GSSAPIContext(); + $gssapicontext->acquireCredentials($ccache); + + $token = ''; + $success = $gssapicontext->initSecContext($this->prefs['gssapi_context'], null, null, null, $token); + $token = base64_encode($token); + } + catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); + return self::ERROR_BAD; + } + + $this->putLine($this->nextTag() . " AUTHENTICATE GSSAPI " . $token); + $line = trim($this->readReply()); + + if ($line[0] != '+') { + return $this->parseResult($line); + } + + try { + $challenge = base64_decode(substr($line, 2)); + $gssapicontext->unwrap($challenge, $challenge); + $gssapicontext->wrap($challenge, $challenge, true); + } + catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); + return self::ERROR_BAD; + } + + $this->putLine(base64_encode($challenge)); + + $line = $this->readReply(); $result = $this->parseResult($line); } else { // PLAIN @@ -738,7 +796,7 @@ return false; } - if (empty($password)) { + if (empty($password) && empty($options['gssapi_cn'])) { $this->setError(self::ERROR_NO, "Empty password"); return false; } @@ -774,7 +832,8 @@ } // Use best (for security) supported authentication method - foreach (array('DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN') as $auth_method) { + $all_methods = array('GSSAPI', 'DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN'); + foreach ($all_methods as $auth_method) { if (in_array($auth_method, $auth_methods)) { break; } @@ -803,6 +862,7 @@ case 'CRAM-MD5': case 'DIGEST-MD5': case 'PLAIN': + case 'GSSAPI': $result = $this->authenticate($user, $password, $auth_method); break; case 'LOGIN': -- Gitblit v1.9.1