Skip to content

Commit d81e805

Browse files
committed
Drop support for hierarchical credentials
Not supported by every backend, making them not interchangeable. To access credentials inside KeePass / Vault groups, the group name needs to be passed to their respective constructors
1 parent eccb526 commit d81e805

File tree

8 files changed

+33
-62
lines changed

8 files changed

+33
-62
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Credentials change log
55

66
## 1.0.0 / 2019-01-26
77

8+
* **Heads up:** Dropped support for hierarchical credentials using forward
9+
slashes. Credential groups in KeePass databases and in Vault can be
10+
accessed by passing the groups' names to their respective constructors.
811
* Require xp-forge/rest-client `^1.0` - @thekid
912

1013
## 0.8.5 / 2019-01-22

src/main/php/security/credentials/FromEnvironment.class.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function open() { return $this; }
2828
* @return util.Secret
2929
*/
3030
public function named($name) {
31-
$name= strtoupper(strtr($name, ['/' => '__']));
31+
$name= strtoupper($name);
3232
if (null === ($value= Environment::variable($name, null))) return null;
3333

3434
$this->remove && $this->unset[$name]= null;
@@ -42,9 +42,9 @@ public function named($name) {
4242
* @return iterable
4343
*/
4444
public function all($pattern) {
45-
$match= strtoupper(strtr(substr($pattern, 0, strrpos($pattern, '*')), ['/' => '__']));
45+
$match= strtoupper(substr($pattern, 0, strrpos($pattern, '*')));
4646
foreach ($_ENV as $name => $value) {
47-
if (0 === strncmp($name, $match, strlen($match))) yield strtr(strtolower($name), ['__' => '/']) => new Secret($value);
47+
if (0 === strncmp($name, $match, strlen($match))) yield strtolower($name) => new Secret($value);
4848
}
4949
}
5050

src/main/php/security/credentials/FromKeePass.class.php

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,8 @@ public function open() {
3737
* @return util.Secret
3838
*/
3939
public function named($name) {
40-
if (false === ($p= strrpos($name, '/'))) {
41-
$group= '/';
42-
$match= $name;
43-
} else {
44-
$group= '/'.substr($name, 0, $p);
45-
$match= substr($name, $p + 1);
46-
}
47-
48-
foreach ($this->db->group($this->group.$group)->passwords() as $path => $value) {
49-
if (basename($path) === $match) return new Secret((string)$value);
40+
foreach ($this->db->group('/'.$this->group)->passwords() as $path => $value) {
41+
if (basename($path) === $name) return new Secret((string)$value);
5042
}
5143
return null;
5244
}
@@ -58,16 +50,10 @@ public function named($name) {
5850
* @return iterable
5951
*/
6052
public function all($pattern) {
61-
if (false === ($p= strrpos($pattern, '/'))) {
62-
$group= '/';
63-
$match= substr($pattern, 0, strrpos($pattern, '*'));
64-
} else {
65-
$group= '/'.substr($pattern, 0, $p);
66-
$match= substr($pattern, $p + 1, strrpos($pattern, '*') - $p - 1);
67-
}
68-
69-
foreach ($this->db->group($this->group.$group)->passwords() as $path => $value) {
70-
if (0 === strncmp(basename($path), $match, strlen($match))) yield substr($path, 1) => new Secret((string)$value);
53+
$match= substr($pattern, 0, strrpos($pattern, '*'));
54+
foreach ($this->db->group('/'.$this->group)->passwords() as $path => $value) {
55+
$base= basename($path);
56+
if (0 === strncmp($base, $match, strlen($match))) yield $base => new Secret((string)$value);
7157
}
7258
}
7359

src/main/php/security/credentials/FromVault.class.php

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,10 @@ public function open() { return $this; }
3737
* @return util.Secret
3838
*/
3939
public function named($name) {
40-
$p= strrpos($name, '/');
41-
$response= $this->endpoint->resource('/v1/secret/'.$this->group.substr($name, 0, $p))->get();
40+
$response= $this->endpoint->resource('/v1/secret/'.$this->group)->get();
4241
if ($response->status() < 400) {
4342
$data= $response->value()['data'];
44-
$key= ltrim(substr($name, $p), '/');
45-
return isset($data[$key]) ? new Secret($data[$key]) : null;
43+
return isset($data[$name]) ? new Secret($data[$name]) : null;
4644
} else {
4745
return null;
4846
}
@@ -55,14 +53,11 @@ public function named($name) {
5553
* @return iterable
5654
*/
5755
public function all($pattern) {
58-
$p= strrpos($pattern, '/');
59-
$group= substr($pattern, 0, $p);
60-
$response= $this->endpoint->resource('/v1/secret/'.$this->group.$group)->get();
56+
$response= $this->endpoint->resource('/v1/secret/'.$this->group)->get();
6157
if ($response->status() < 400) {
62-
$key= ltrim(substr($pattern, $p), '/');
63-
$match= substr($key, 0, strrpos($key, '*'));
58+
$match= substr($pattern, 0, strrpos($pattern, '*'));
6459
foreach ($response->value()['data'] as $name => $value) {
65-
if (0 === strncmp($name, $match, strlen($match))) yield ltrim($group.'/'.$name, '/') => new Secret($value);
60+
if (0 === strncmp($name, $match, strlen($match))) yield $name => new Secret($value);
6661
}
6762
}
6863
}

src/test/php/security/credentials/unittest/AbstractSecretsTest.class.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ protected abstract function newFixture();
88
/**
99
* Assertion helper
1010
*
11+
* @param security.valuts.Secrets $fixture
1112
* @param string $expected
1213
* @param string $name
1314
* @return void
1415
* @throws unittest.AssertionFailedError
1516
*/
16-
protected function assertCredential($expected, $name) {
17-
$fixture= $this->newFixture();
17+
protected function assertCredential($fixture, $expected, $name) {
1818
$fixture->open();
1919
try {
2020
$this->assertEquals($expected, $fixture->named($name)->reveal());
@@ -26,13 +26,13 @@ protected function assertCredential($expected, $name) {
2626
/**
2727
* Assertion helper
2828
*
29+
* @param security.valuts.Secrets $fixture
2930
* @param [:string] $expected
3031
* @param string $pattern
3132
* @return void
3233
* @throws unittest.AssertionFailedError
3334
*/
34-
protected function assertCredentials($expected, $pattern) {
35-
$fixture= $this->newFixture();
35+
protected function assertCredentials($fixture, $expected, $pattern) {
3636
$fixture->open();
3737
try {
3838
$this->assertEquals($expected, array_map(
@@ -60,7 +60,7 @@ public function open_and_close_can_be_called_twice() {
6060
# ['prod_master_key', 'master']
6161
#])]
6262
public function credential($name, $result) {
63-
$this->assertCredential($result, $name);
63+
$this->assertCredential($this->newFixture(), $result, $name);
6464
}
6565

6666
#[@test, @values([
@@ -69,17 +69,7 @@ public function credential($name, $result) {
6969
# ['non_existant_*', []]
7070
#])]
7171
public function credentials($filter, $result) {
72-
$this->assertCredentials($result, $filter);
73-
}
74-
75-
#[@test]
76-
public function from_subfolder() {
77-
$this->assertCredential('test', 'xp/app/mysql');
78-
}
79-
80-
#[@test]
81-
public function all_in_subfolder() {
82-
$this->assertCredentials(['xp/app/mysql' => 'test'], 'xp/app/*');
72+
$this->assertCredentials($this->newFixture(), $result, $filter);
8373
}
8474

8575
#[@test]

src/test/php/security/credentials/unittest/FromEnvironmentTest.class.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php namespace security\credentials\unittest;
22

3+
use lang\Environment;
34
use security\credentials\FromEnvironment;
45
use util\Secret;
5-
use lang\Environment;
66

77
class FromEnvironmentTest extends AbstractSecretsTest {
88

@@ -15,7 +15,6 @@ public function setUp() {
1515
'TEST_DB_PASSWORD' => 'db',
1616
'TEST_LDAP_PASSWORD' => 'ldap',
1717
'PROD_MASTER_KEY' => 'master',
18-
'XP__APP__MYSQL' => 'test'
1918
]);
2019
}
2120

src/test/php/security/credentials/unittest/FromFileTest.class.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php namespace security\credentials\unittest;
22

3-
use security\credentials\FromFile;
43
use io\File;
54
use io\TempFile;
6-
use io\streams\Streams;
75
use io\streams\MemoryInputStream;
6+
use io\streams\Streams;
7+
use security\credentials\FromFile;
88

99
class FromFileTest extends AbstractSecretsTest {
1010

@@ -14,7 +14,6 @@ protected function newFixture() {
1414
"TEST_DB_PASSWORD=db\n".
1515
"TEST_LDAP_PASSWORD=ldap\n".
1616
"PROD_MASTER_KEY=master\n".
17-
"XP/APP/MYSQL=test\n".
1817
"CLOUD_SECRET=S\\xa7T"
1918
)));
2019
}
@@ -47,6 +46,6 @@ public function can_optionally_be_removed_after_close() {
4746

4847
#[@test]
4948
public function byte_escape_sequence() {
50-
$this->assertCredential("S\xa7T", 'cloud_secret');
49+
$this->assertCredential($this->newFixture(), "S\xa7T", 'cloud_secret');
5150
}
5251
}

src/test/php/security/credentials/unittest/FromKeePassTest.class.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@ protected function newFixture($group= '/') {
1717

1818
#[@test, @values(['xp/app', '/xp/app', '/xp/app/'])]
1919
public function using_group($group) {
20-
$fixture= $this->newFixture($group);
21-
$fixture->open();
22-
try {
23-
$this->assertEquals('test', $fixture->named('mysql')->reveal());
24-
} finally {
25-
$fixture->close();
26-
}
20+
$this->assertCredential($this->newFixture($group), 'test', 'mysql');
21+
}
22+
23+
#[@test, @values(['xp/app', '/xp/app', '/xp/app/'])]
24+
public function all_in_group($group) {
25+
$this->assertCredentials($this->newFixture($group), ['mysql' => 'test'], '*');
2726
}
2827
}

0 commit comments

Comments
 (0)