[aur-dev] [PATCH/RFC 1/5] Add support for adding SSH public keys to profiles

Lukas Fleischer archlinux at cryptocrack.de
Tue Jun 17 14:22:49 EDT 2014


Users can now add an SSH public key on the account edit page. This will
later be used to authenticate users via SSH.

Signed-off-by: Lukas Fleischer <archlinux at cryptocrack.de>
---
 UPGRADING                          | 10 ++++-
 schema/aur-schema.sql              |  1 +
 web/html/account.php               |  7 ++--
 web/lib/acctfuncs.inc.php          | 78 ++++++++++++++++++++++++++++++++++----
 web/template/account_edit_form.php |  5 +++
 5 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/UPGRADING b/UPGRADING
index 863fde3..2e1b806 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -1,6 +1,15 @@
 Upgrading
 =========
 
+From 3.1.0 to 4.0.0
+-------------------
+
+1. Add a field for the SSH public key to the Users table:
+
+----
+ALTER TABLE Users ADD COLUMN SSHPubKey VARCHAR(4096) NULL DEFAULT NULL;
+----
+
 From 3.0.0 to 3.1.0
 -------------------
 
@@ -16,7 +25,6 @@ ALTER TABLE Licenses MODIFY Name VARCHAR(255) NOT NULL;
 ALTER TABLE Groups MODIFY Name VARCHAR(255) NOT NULL;
 ALTER TABLE PackageDepends MODIFY DepCondition VARCHAR(255);
 ALTER TABLE PackageRelations MODIFY RelCondition VARCHAR(255);
-----
 
 From 2.3.1 to 3.0.0
 -------------------
diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql
index 0efae93..750ee21 100644
--- a/schema/aur-schema.sql
+++ b/schema/aur-schema.sql
@@ -32,6 +32,7 @@ CREATE TABLE Users (
 	LangPreference VARCHAR(5) NOT NULL DEFAULT 'en',
 	IRCNick VARCHAR(32) NOT NULL DEFAULT '',
 	PGPKey VARCHAR(40) NULL DEFAULT NULL,
+	SSHPubKey VARCHAR(4096) NULL DEFAULT NULL,
 	LastLogin BIGINT UNSIGNED NOT NULL DEFAULT 0,
 	LastLoginIPAddress INTEGER UNSIGNED NOT NULL DEFAULT 0,
 	InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0,
diff --git a/web/html/account.php b/web/html/account.php
index 47cf6d2..aef240a 100644
--- a/web/html/account.php
+++ b/web/html/account.php
@@ -52,7 +52,7 @@ if (isset($_COOKIE["AURSID"])) {
 				display_account_form($atype, "UpdateAccount", $row["Username"],
 					$row["AccountTypeID"], $row["Suspended"], $row["Email"],
 					"", "", $row["RealName"], $row["LangPreference"],
-					$row["IRCNick"], $row["PGPKey"],
+					$row["IRCNick"], $row["PGPKey"], $row["SSHPubKey"],
 					$row["InactivityTS"] ? 1 : 0, $row["ID"]);
 			} else {
 				print __("You do not have permission to edit this account.");
@@ -82,7 +82,8 @@ if (isset($_COOKIE["AURSID"])) {
 					in_request("U"), in_request("T"), in_request("S"),
 					in_request("E"), in_request("P"), in_request("C"),
 					in_request("R"), in_request("L"), in_request("I"),
-					in_request("K"), in_request("J"), in_request("ID"));
+					in_request("K"), in_request("PK"), in_request("J"),
+					in_request("ID"));
 		}
 	} else {
 		if ($atype == "Trusted User" || $atype == "Developer") {
@@ -113,7 +114,7 @@ if (isset($_COOKIE["AURSID"])) {
 		# display the account request form
 		#
 		print __("Use this form to create an account.");
-		display_account_form("", "NewAccount", "", "", "", "", "", "", "", $LANG);
+		display_account_form("", "NewAccount", "", "", "", "", "", "", "", "", $LANG);
 	}
 }
 
diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php
index 06d4311..d7578a8 100644
--- a/web/lib/acctfuncs.inc.php
+++ b/web/lib/acctfuncs.inc.php
@@ -54,13 +54,14 @@ function html_format_pgp_fingerprint($fingerprint) {
  * @param string $L The language preference of the displayed user
  * @param string $I The IRC nickname of the displayed user
  * @param string $K The PGP key fingerprint of the displayed user
+ * @param string $PK The SSH public key of the displayed user
  * @param string $J The inactivity status of the displayed user
  * @param string $UID The user ID of the displayed user
  *
  * @return void
  */
-function display_account_form($UTYPE,$A,$U="",$T="",$S="",
-		$E="",$P="",$C="",$R="",$L="",$I="",$K="",$J="", $UID=0) {
+function display_account_form($UTYPE,$A,$U="",$T="",$S="",$E="",$P="",$C="",
+		$R="",$L="",$I="",$K="",$PK="",$J="", $UID=0) {
 	global $SUPPORTED_LANGS;
 
 	include("account_edit_form.php");
@@ -84,13 +85,14 @@ function display_account_form($UTYPE,$A,$U="",$T="",$S="",
  * @param string $L The language preference of the user
  * @param string $I The IRC nickname of the user
  * @param string $K The PGP fingerprint of the user
+ * @param string $PK The SSH public key of the user
  * @param string $J The inactivity status of the user
  * @param string $UID The user ID of the modified account
  *
  * @return string|void Return void if successful, otherwise return error
  */
-function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
-			$P="",$C="",$R="",$L="",$I="",$K="",$J="",$UID=0) {
+function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",$P="",
+		$C="",$R="",$L="",$I="",$K="",$PK="",$J="",$UID=0) {
 	global $SUPPORTED_LANGS, $AUR_LOCATION;
 
 	$error = '';
@@ -143,6 +145,15 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
 		$error = __("The PGP key fingerprint is invalid.");
 	}
 
+	if (!$error && !empty($PK)) {
+		if (valid_ssh_pubkey($PK)) {
+			$tokens = explode(" ", $PK);
+			$PK = $tokens[0] . " " . $tokens[1];
+		} else {
+			$error = __("The SSH public key is invalid.");
+		}
+	}
+
 	if (($UTYPE == "User" && $T > 1) || ($UTYPE == "Trusted User" && $T > 2)) {
 		$error = __("Cannot increase account permissions.");
 	}
@@ -185,11 +196,29 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
 					"<strong>", htmlspecialchars($E,ENT_QUOTES), "</strong>");
 		}
 	}
+	if (!$error) {
+		/*
+		 * Check whether the SSH public key is available.
+		 * TODO: Fix race condition.
+		 */
+		$q = "SELECT COUNT(*) FROM Users ";
+		$q.= "WHERE SSHPubKey = " . $dbh->quote($PK);
+		if ($TYPE == "edit") {
+			$q.= " AND ID != " . intval($UID);
+		}
+		$result = $dbh->query($q);
+		$row = $result->fetch(PDO::FETCH_NUM);
+
+		if ($row[0]) {
+			$error = __("The SSH public key, %s%s%s, is already in use.",
+					"<strong>", htmlspecialchars($PK, ENT_QUOTES), "</strong>");
+		}
+	}
 
 	if ($error) {
 		print "<ul class='errorlist'><li>".$error."</li></ul>\n";
 		display_account_form($UTYPE, $A, $U, $T, $S, $E, "", "",
-				$R, $L, $I, $K, $J, $UID);
+				$R, $L, $I, $K, $PK, $J, $UID);
 		return;
 	}
 
@@ -211,11 +240,13 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
 		$L = $dbh->quote($L);
 		$I = $dbh->quote($I);
 		$K = $dbh->quote(str_replace(" ", "", $K));
+		$PK = $dbh->quote($PK);
 		$q = "INSERT INTO Users (AccountTypeID, Suspended, ";
 		$q.= "InactivityTS, Username, Email, Passwd, Salt, ";
-		$q.= "RealName, LangPreference, IRCNick, PGPKey) ";
+		$q.= "RealName, LangPreference, IRCNick, PGPKey, ";
+		$q.= "SSHPubKey) ";
 		$q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, ";
-		$q.= "$I, $K)";
+		$q.= "$I, $K, $PK)";
 		$result = $dbh->exec($q);
 		if (!$result) {
 			print __("Error trying to create account, %s%s%s.",
@@ -283,6 +314,7 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
 		$q.= ", LangPreference = " . $dbh->quote($L);
 		$q.= ", IRCNick = " . $dbh->quote($I);
 		$q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K));
+		$q.= ", SSHPubKey = " . $dbh->quote($PK);
 		$q.= ", InactivityTS = " . $inactivity_ts;
 		$q.= " WHERE ID = ".intval($UID);
 		$result = $dbh->exec($q);
@@ -797,6 +829,38 @@ function valid_pgp_fingerprint($fingerprint) {
 }
 
 /**
+ * Determine if the SSH public key is valid
+ *
+ * @param string $pubkey SSH public key to check
+ *
+ * @return bool True if the SSH public key is valid, otherwise false
+ */
+function valid_ssh_pubkey($pubkey) {
+	$valid_prefixes = array(
+		"ssh-rsa", "ssh-dss", "ecdsa-sha2-nistp256",
+		"ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "ssh-ed25519"
+	);
+
+	$has_valid_prefix = false;
+	foreach ($valid_prefixes as $prefix) {
+		if (strpos($pubkey, $prefix . " ") === 0) {
+			$has_valid_prefix = true;
+			break;
+		}
+	}
+	if (!$has_valid_prefix) {
+		return false;
+	}
+
+	$tokens = explode(" ", $pubkey);
+	if (empty($tokens[1])) {
+		return false;
+	}
+
+	return (base64_encode(base64_decode($tokens[1], true)) == $tokens[1]);
+}
+
+/**
  * Determine if the user account has been suspended
  *
  * @param string $id The ID of user to check if suspended
diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php
index 30b26fd..767b227 100644
--- a/web/template/account_edit_form.php
+++ b/web/template/account_edit_form.php
@@ -93,6 +93,11 @@
 		</p>
 
 		<p>
+			<label for="id_ssh"><?= __("SSH Public Key") ?>:</label>
+			<textarea name="PK" id="id_ssh" rows="5" cols="30"><?= htmlspecialchars($PK) ?></textarea>
+		</p>
+
+		<p>
 			<label for="id_language"><?= __("Language") ?>:</label>
 			<select name="L" id="id_language">
 <?php
-- 
2.0.0



More information about the aur-dev mailing list