Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F78489
D7462.diff
All Users
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D7462.diff
View Options
diff --git a/resources/sql/patches/20131031.vcspassword.sql b/resources/sql/patches/20131031.vcspassword.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/patches/20131031.vcspassword.sql
@@ -0,0 +1,8 @@
+CREATE TABLE {$NAMESPACE}_repository.repository_vcspassword (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ userPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ passwordHash VARCHAR(50) NOT NULL COLLATE utf8_bin,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_phid` (userPHID)
+) ENGINE=InnoDB, CHARSET utf8;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -535,6 +535,7 @@
'DiffusionSSHGitUploadPackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php',
'DiffusionSSHGitWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitWorkflow.php',
'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php',
+ 'DiffusionSetPasswordPanel' => 'applications/diffusion/panel/DiffusionSetPasswordPanel.php',
'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php',
'DiffusionStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionStableCommitNameQuery.php',
'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionSvnCommitParentsQuery.php',
@@ -1674,6 +1675,7 @@
'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php',
'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php',
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
+ 'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php',
'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php',
@@ -2729,6 +2731,7 @@
'DiffusionSSHGitUploadPackWorkflow' => 'DiffusionSSHGitWorkflow',
'DiffusionSSHGitWorkflow' => 'DiffusionSSHWorkflow',
'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow',
+ 'DiffusionSetPasswordPanel' => 'PhabricatorSettingsPanel',
'DiffusionSetupException' => 'AphrontUsageException',
'DiffusionStableCommitNameQuery' => 'DiffusionQuery',
'DiffusionSvnCommitParentsQuery' => 'DiffusionCommitParentsQuery',
@@ -4015,6 +4018,7 @@
'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase',
'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorSSHWorkflow' => 'PhutilArgumentWorkflow',
'PhabricatorSavedQuery' =>
diff --git a/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php b/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
--- a/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
+++ b/src/applications/diffusion/config/PhabricatorDiffusionConfigOptions.php
@@ -84,6 +84,24 @@
'Regular expression to link external bug tracker. See '.
'http://tortoisesvn.net/docs/release/TortoiseSVN_en/'.
'tsvn-dug-bugtracker.html for further explanation.')),
+ $this->newOption('diffusion.allow-http-auth', 'bool', false)
+ ->setBoolOptions(
+ array(
+ pht('Allow HTTP Basic Auth'),
+ pht('Disable HTTP Basic Auth'),
+ ))
+ ->setSummary(pht('Enable HTTP Basic Auth for repositories.'))
+ ->setDescription(
+ pht(
+ "Phabricator can serve repositories over HTTP, using HTTP basic ".
+ "auth.\n\n".
+ "Because HTTP basic auth is less secure than SSH auth, it is ".
+ "disabled by default. You can enable it here if you'd like to use ".
+ "it anyway. There's nothing fundamentally insecure about it as ".
+ "long as Phabricator uses HTTPS, but it presents a much lower ".
+ "barrier to attackers than SSH does.\n\n".
+ "Consider using SSH for authenticated access to repositories ".
+ "instead of HTTP."))
);
}
diff --git a/src/applications/diffusion/panel/DiffusionSetPasswordPanel.php b/src/applications/diffusion/panel/DiffusionSetPasswordPanel.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/panel/DiffusionSetPasswordPanel.php
@@ -0,0 +1,209 @@
+<?php
+
+final class DiffusionSetPasswordPanel extends PhabricatorSettingsPanel {
+
+ public function getPanelKey() {
+ return 'vcspassword';
+ }
+
+ public function getPanelName() {
+ return pht('VCS Password');
+ }
+
+ public function getPanelGroup() {
+ return pht('Authentication');
+ }
+
+ public function isEnabled() {
+ return PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth');
+ }
+
+ public function processRequest(AphrontRequest $request) {
+ $user = $request->getUser();
+
+ $vcspassword = id(new PhabricatorRepositoryVCSPassword())
+ ->loadOneWhere(
+ 'userPHID = %s',
+ $user->getPHID());
+ if (!$vcspassword) {
+ $vcspassword = id(new PhabricatorRepositoryVCSPassword());
+ $vcspassword->setUserPHID($user->getPHID());
+ }
+
+ $panel_uri = $this->getPanelURI('?saved=true');
+
+ $errors = array();
+
+ $e_password = true;
+ $e_confirm = true;
+
+ if ($request->isFormPost()) {
+ if ($request->getBool('remove')) {
+ if ($vcspassword->getID()) {
+ $vcspassword->delete();
+ return id(new AphrontRedirectResponse())->setURI($panel_uri);
+ }
+ }
+
+ $new_password = $request->getStr('password');
+ $confirm = $request->getStr('confirm');
+ if (!strlen($new_password)) {
+ $e_password = pht('Required');
+ $errors[] = pht('Password is required.');
+ } else {
+ $e_password = null;
+ }
+
+ if (!strlen($confirm)) {
+ $e_confirm = pht('Required');
+ $errors[] = pht('You must confirm the new password.');
+ } else {
+ $e_confirm = null;
+ }
+
+ if (!$errors) {
+ $envelope = new PhutilOpaqueEnvelope($new_password);
+
+ if ($new_password !== $confirm) {
+ $e_password = pht('Does Not Match');
+ $e_confirm = pht('Does Not Match');
+ $errors[] = pht('Password and confirmation do not match.');
+ } else if ($user->comparePassword($envelope)) {
+ $e_password = pht('Not Unique');
+ $e_confirm = pht('Not Unique');
+ $errors[] = pht(
+ 'This password is not unique. You must use a unique password.');
+ }
+
+ if (!$errors) {
+ $vcspassword->setPassword($envelope, $user);
+ $vcspassword->save();
+
+ return id(new AphrontRedirectResponse())->setURI($panel_uri);
+ }
+ }
+ }
+
+ $title = pht('Set VCS Password');
+
+ $error_view = null;
+ if ($errors) {
+ $error_view = id(new AphrontErrorView())
+ ->setTitle(pht('Form Errors'))
+ ->setErrors($errors);
+ }
+
+ $form = id(new AphrontFormView())
+ ->setUser($user)
+ ->appendRemarkupInstructions(
+ pht(
+ 'To access repositories hosted by Phabricator over HTTP, you must '.
+ 'set a version control password. This password should be unique.'.
+ "\n\n".
+ "This password applies to all repositories available over ".
+ "HTTP."));
+
+ if ($vcspassword->getID()) {
+ $form
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setLabel(pht('Current Password'))
+ ->setDisabled(true)
+ ->setValue('********************'));
+ } else {
+ $form
+ ->appendChild(
+ id(new AphrontFormMarkupControl())
+ ->setLabel(pht('Current Password'))
+ ->setValue(phutil_tag('em', array(), pht('No Password Set'))));
+ }
+
+ $form
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setName('password')
+ ->setLabel(pht('New VCS Password'))
+ ->setError($e_password))
+ ->appendChild(
+ id(new AphrontFormPasswordControl())
+ ->setName('confirm')
+ ->setLabel(pht('Confirm VCS Password'))
+ ->setError($e_confirm))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Change Password')));
+
+
+ if (!$vcspassword->getID()) {
+ $is_serious = PhabricatorEnv::getEnvConfig(
+ 'phabricator.serious-business');
+
+ $suggest = Filesystem::readRandomBytes(128);
+ $suggest = preg_replace('([^A-Za-z0-9/!().,;{}^&*%~])', '', $suggest);
+ $suggest = substr($suggest, 0, 20);
+
+ if ($is_serious) {
+ $form->appendRemarkupInstructions(
+ pht(
+ 'Having trouble coming up with a good password? Try this randomly '.
+ 'generated one, made by a computer:'.
+ "\n\n".
+ "`%s`",
+ $suggest));
+ } else {
+ $form->appendRemarkupInstructions(
+ pht(
+ 'Having trouble coming up with a good password? Try this '.
+ 'artisinal password, hand made in small batches by our expert '.
+ 'craftspeople: '.
+ "\n\n".
+ "`%s`",
+ $suggest));
+ }
+ }
+
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeaderText($title)
+ ->setForm($form)
+ ->setFormError($error_view);
+
+ $remove_form = id(new AphrontFormView())
+ ->setUser($user);
+
+ if ($vcspassword->getID()) {
+ $remove_form
+ ->addHiddenInput('remove', true)
+ ->appendRemarkupInstructions(
+ pht(
+ 'You can remove your VCS password, which will prevent your '.
+ 'account from accessing repositories.'))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Remove Password')));
+ } else {
+ $remove_form->appendRemarkupInstructions(
+ pht(
+ 'You do not currently have a VCS password set. If you set one, you '.
+ 'can remove it here later.'));
+ }
+
+ $remove_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Remove VCS Password'))
+ ->setForm($remove_form);
+
+ $saved = null;
+ if ($request->getBool('saved')) {
+ $saved = id(new AphrontErrorView())
+ ->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
+ ->setTitle(pht('Password Updated'))
+ ->appendChild(pht('Your VCS password has been updated.'));
+ }
+
+ return array(
+ $saved,
+ $object_box,
+ $remove_box,
+ );
+ }
+
+}
diff --git a/src/applications/repository/storage/PhabricatorRepositoryVCSPassword.php b/src/applications/repository/storage/PhabricatorRepositoryVCSPassword.php
new file mode 100644
--- /dev/null
+++ b/src/applications/repository/storage/PhabricatorRepositoryVCSPassword.php
@@ -0,0 +1,34 @@
+<?php
+
+final class PhabricatorRepositoryVCSPassword extends PhabricatorRepositoryDAO {
+
+ protected $id;
+ protected $userPHID;
+ protected $passwordHash;
+
+ public function setPassword(
+ PhutilOpaqueEnvelope $password,
+ PhabricatorUser $user) {
+ return $this->setPasswordHash($this->hashPassword($password, $user));
+ }
+
+ public function comparePassword(
+ PhutilOpaqueEnvelope $password,
+ PhabricatorUser $user) {
+
+ $hash = $this->hashPassword($password, $user);
+ return ($hash == $this->getPasswordHash());
+ }
+
+ private function hashPassword(
+ PhutilOpaqueEnvelope $password,
+ PhabricatorUser $user) {
+
+ if ($user->getPHID() != $this->getUserPHID()) {
+ throw new Exception("User does not match password user PHID!");
+ }
+
+ return PhabricatorHash::digestPassword($password, $user->getPHID());
+ }
+
+}
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1716,6 +1716,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('20131030.repostatusmessage.sql'),
),
+ '20131031.vcspassword.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131031.vcspassword.sql'),
+ ),
);
}
}
diff --git a/src/infrastructure/util/PhabricatorHash.php b/src/infrastructure/util/PhabricatorHash.php
--- a/src/infrastructure/util/PhabricatorHash.php
+++ b/src/infrastructure/util/PhabricatorHash.php
@@ -24,6 +24,24 @@
/**
+ * Digest a string into a password hash. This is similar to @{method:digest},
+ * but requires a salt and iterates the hash to increase cost.
+ */
+ public static function digestPassword(PhutilOpaqueEnvelope $envelope, $salt) {
+ $result = $envelope->openEnvelope();
+ if (!$result) {
+ throw new Exception("Trying to digest empty password!");
+ }
+
+ for ($ii = 0; $ii < 1000; $ii++) {
+ $result = PhabricatorHash::digest($result, $salt);
+ }
+
+ return $result;
+ }
+
+
+ /**
* Digest a string for use in, e.g., a MySQL index. This produces a short
* (12-byte), case-sensitive alphanumeric string with 72 bits of entropy,
* which is generally safe in most contexts (notably, URLs).
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/vq/gj/mgntpdqfl3wujyhm
Default Alt Text
D7462.diff (13 KB)
Attached To
Mode
D7462: Implementation of VCS passwords against user.
Attached
Detach File
Event Timeline
Log In to Comment