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