Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/auth/storage/PhabricatorAuthPassword.php
12256 views
1
<?php
2
3
final class PhabricatorAuthPassword
4
extends PhabricatorAuthDAO
5
implements
6
PhabricatorPolicyInterface,
7
PhabricatorDestructibleInterface,
8
PhabricatorApplicationTransactionInterface {
9
10
protected $objectPHID;
11
protected $passwordType;
12
protected $passwordHash;
13
protected $passwordSalt;
14
protected $isRevoked;
15
protected $legacyDigestFormat;
16
17
private $object = self::ATTACHABLE;
18
19
const PASSWORD_TYPE_ACCOUNT = 'account';
20
const PASSWORD_TYPE_VCS = 'vcs';
21
const PASSWORD_TYPE_TEST = 'test';
22
23
public static function initializeNewPassword(
24
PhabricatorAuthPasswordHashInterface $object,
25
$type) {
26
27
return id(new self())
28
->setObjectPHID($object->getPHID())
29
->attachObject($object)
30
->setPasswordType($type)
31
->setIsRevoked(0);
32
}
33
34
protected function getConfiguration() {
35
return array(
36
self::CONFIG_AUX_PHID => true,
37
self::CONFIG_COLUMN_SCHEMA => array(
38
'passwordType' => 'text64',
39
'passwordHash' => 'text128',
40
'passwordSalt' => 'text64',
41
'isRevoked' => 'bool',
42
'legacyDigestFormat' => 'text32?',
43
),
44
self::CONFIG_KEY_SCHEMA => array(
45
'key_role' => array(
46
'columns' => array('objectPHID', 'passwordType'),
47
),
48
),
49
) + parent::getConfiguration();
50
}
51
52
public function getPHIDType() {
53
return PhabricatorAuthPasswordPHIDType::TYPECONST;
54
}
55
56
public function getObject() {
57
return $this->assertAttached($this->object);
58
}
59
60
public function attachObject($object) {
61
$this->object = $object;
62
return $this;
63
}
64
65
public function getHasher() {
66
$hash = $this->newPasswordEnvelope();
67
return PhabricatorPasswordHasher::getHasherForHash($hash);
68
}
69
70
public function canUpgrade() {
71
// If this password uses a legacy digest format, we can upgrade it to the
72
// new digest format even if a better hasher isn't available.
73
if ($this->getLegacyDigestFormat() !== null) {
74
return true;
75
}
76
77
$hash = $this->newPasswordEnvelope();
78
return PhabricatorPasswordHasher::canUpgradeHash($hash);
79
}
80
81
public function upgradePasswordHasher(
82
PhutilOpaqueEnvelope $envelope,
83
PhabricatorAuthPasswordHashInterface $object) {
84
85
// Before we make changes, double check that this is really the correct
86
// password. It could be really bad if we "upgraded" a password and changed
87
// the secret!
88
89
if (!$this->comparePassword($envelope, $object)) {
90
throw new Exception(
91
pht(
92
'Attempting to upgrade password hasher, but the password for the '.
93
'upgrade is not the stored credential!'));
94
}
95
96
return $this->setPassword($envelope, $object);
97
}
98
99
public function setPassword(
100
PhutilOpaqueEnvelope $password,
101
PhabricatorAuthPasswordHashInterface $object) {
102
103
$hasher = PhabricatorPasswordHasher::getBestHasher();
104
return $this->setPasswordWithHasher($password, $object, $hasher);
105
}
106
107
public function setPasswordWithHasher(
108
PhutilOpaqueEnvelope $password,
109
PhabricatorAuthPasswordHashInterface $object,
110
PhabricatorPasswordHasher $hasher) {
111
112
if (!strlen($password->openEnvelope())) {
113
throw new Exception(
114
pht('Attempting to set an empty password!'));
115
}
116
117
// Generate (or regenerate) the salt first.
118
$new_salt = Filesystem::readRandomCharacters(64);
119
$this->setPasswordSalt($new_salt);
120
121
// Clear any legacy digest format to force a modern digest.
122
$this->setLegacyDigestFormat(null);
123
124
$digest = $this->digestPassword($password, $object);
125
$hash = $hasher->getPasswordHashForStorage($digest);
126
$raw_hash = $hash->openEnvelope();
127
128
return $this->setPasswordHash($raw_hash);
129
}
130
131
public function comparePassword(
132
PhutilOpaqueEnvelope $password,
133
PhabricatorAuthPasswordHashInterface $object) {
134
135
$digest = $this->digestPassword($password, $object);
136
$hash = $this->newPasswordEnvelope();
137
138
return PhabricatorPasswordHasher::comparePassword($digest, $hash);
139
}
140
141
public function newPasswordEnvelope() {
142
return new PhutilOpaqueEnvelope($this->getPasswordHash());
143
}
144
145
private function digestPassword(
146
PhutilOpaqueEnvelope $password,
147
PhabricatorAuthPasswordHashInterface $object) {
148
149
$object_phid = $object->getPHID();
150
151
if ($this->getObjectPHID() !== $object->getPHID()) {
152
throw new Exception(
153
pht(
154
'This password is associated with an object PHID ("%s") for '.
155
'a different object than the provided one ("%s").',
156
$this->getObjectPHID(),
157
$object->getPHID()));
158
}
159
160
$digest = $object->newPasswordDigest($password, $this);
161
162
if (!($digest instanceof PhutilOpaqueEnvelope)) {
163
throw new Exception(
164
pht(
165
'Failed to digest password: object ("%s") did not return an '.
166
'opaque envelope with a password digest.',
167
$object->getPHID()));
168
}
169
170
return $digest;
171
}
172
173
174
175
/* -( PhabricatorPolicyInterface )----------------------------------------- */
176
177
178
public function getCapabilities() {
179
return array(
180
PhabricatorPolicyCapability::CAN_VIEW,
181
PhabricatorPolicyCapability::CAN_EDIT,
182
);
183
}
184
185
public function getPolicy($capability) {
186
return PhabricatorPolicies::getMostOpenPolicy();
187
}
188
189
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
190
return false;
191
}
192
193
194
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
195
196
197
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
198
return array(
199
array($this->getObject(), $capability),
200
);
201
}
202
203
204
/* -( PhabricatorDestructibleInterface )----------------------------------- */
205
206
207
public function destroyObjectPermanently(
208
PhabricatorDestructionEngine $engine) {
209
$this->delete();
210
}
211
212
213
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
214
215
216
public function getApplicationTransactionEditor() {
217
return new PhabricatorAuthPasswordEditor();
218
}
219
220
public function getApplicationTransactionTemplate() {
221
return new PhabricatorAuthPasswordTransaction();
222
}
223
224
}
225
226