Passed
Push — master ( 5a582b...461cd7 )
by Thomas
02:36
created

MemberKeyProvider   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 17
eloc 28
c 1
b 0
f 0
dl 0
loc 118
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 3
A getTenant() 0 6 2
A getTenantFromRow() 0 7 2
A setActiveTenant() 0 7 3
A getForcedTenant() 0 3 1
A getActiveTenant() 0 13 4
A injectTenantMetadata() 0 5 1
A setForcedTenant() 0 4 1
1
<?php
2
3
namespace LeKoala\Encrypt;
4
5
use ParagonIE\CipherSweet\Exception\CipherSweetException;
6
use ParagonIE\CipherSweet\KeyProvider\MultiTenantProvider;
7
use SilverStripe\Security\Security;
8
9
/**
10
 * This class provides a multi tenant key provider
11
 * Each user gets its own key to encrypt its data
12
 *
13
 * - getTenant() selects a KeyProvider based on a given tenant.
14
 * - getTenantFromRow() gets the tenant ID (array key) based on the data stored in an encrypted row.
15
 * - injectTenantMetadata() injects some breadcrumb for getTenantFromRow() to use to select the appropriate key.
16
 *
17
 * These methods were designed to be generalizable:
18
 * If you implement AWS KMS support, for example, you'd probably store an encrypted data key with injectTenantMetadata()
19
 * and then ask KMS to decrypt it in getTenantFromRow() (unless it's cached).
20
 */
21
class MemberKeyProvider extends MultiTenantProvider
22
{
23
    /**
24
     * @var int
25
     */
26
    protected $forcedTenant;
27
28
    /**
29
     * MemberKeyProvider constructor.
30
     *
31
     * @param array<array-key, KeyProviderInterface> $keyProviders
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, KeyProviderInterface> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, KeyProviderInterface>.
Loading history...
32
     * @param array-key|null $active
33
     */
34
    public function __construct(array $keyProviders, $active = null)
35
    {
36
        if ($active === null && Security::getCurrentUser()) {
37
            $active = Security::getCurrentUser()->ID;
38
        }
39
        parent::__construct($keyProviders, $active);
40
    }
41
42
    /**
43
     * @param array-key $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
44
     * @return KeyProviderInterface
45
     * @throws CipherSweetException
46
     */
47
    public function getTenant($name)
48
    {
49
        if (!array_key_exists($name, $this->tenants)) {
50
            throw new CipherSweetException("Tenant '{$name}' does not exist");
51
        }
52
        return $this->tenants[$this->active];
53
    }
54
55
    /**
56
     * @return KeyProviderInterface
0 ignored issues
show
Bug introduced by
The type LeKoala\Encrypt\KeyProviderInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
57
     * @throws CipherSweetException
58
     */
59
    public function getActiveTenant()
60
    {
61
        if ($this->forcedTenant) {
62
            return $this->tenants[$this->forcedTenant];
63
        }
64
        $this->active = Security::getCurrentUser()->ID ?? $this->active;
65
        if (is_null($this->active)) {
66
            throw new CipherSweetException('Active tenant not set');
67
        }
68
        if (!array_key_exists($this->active, $this->tenants)) {
69
            throw new CipherSweetException("Tenant '{$this->active}' does not exist");
70
        }
71
        return $this->tenants[$this->active];
72
    }
73
74
    /**
75
     * @param array-key $index
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
76
     * @return self
77
     */
78
    public function setActiveTenant($index)
79
    {
80
        if (!$index && Security::getCurrentUser()) {
81
            $index = Security::getCurrentUser();
82
        }
83
        $this->active = $index;
84
        return $this;
85
    }
86
87
    /**
88
     * @return int
89
     */
90
    public function getForcedTenant()
91
    {
92
        return $this->forcedTenant;
93
    }
94
95
    /**
96
     * @param int $index
97
     * @return self
98
     */
99
    public function setForcedTenant($index)
100
    {
101
        $this->forcedTenant = $index;
102
        return $this;
103
    }
104
105
    /**
106
     * Given a row of data, determine which tenant should be selected.
107
     *
108
     * This is not super useful since we mostly go through the ORM
109
     *
110
     * @param array $row
111
     * @param string $tableName
112
     * @return string
113
     *
114
     * @throws CipherSweetException
115
     */
116
    public function getTenantFromRow(array $row, $tableName)
117
    {
118
        // Expect member bound encryption to have a Member relation
119
        if (isset($row['MemberID'])) {
120
            return $row['MemberID'];
121
        }
122
        return $this->active;
123
    }
124
125
    /**
126
     * This is called when you encrypt a row, extra fields can be added
127
     * It's not really used in our case because we encrypt each fields
128
     * one by one anyway
129
     *
130
     * @param array $row
131
     * @param string $tableName
132
     * @return array
133
     */
134
    public function injectTenantMetadata(array $row, $tableName)
135
    {
136
        // If our class uses encryption per user, inject member id
137
        $row['MemberID'] = $this->active;
138
        return $row;
139
    }
140
}
141