Passed
Push — master ( 5723e1...675cd9 )
by Nils
02:43
created

AuthorizedKeysCollector::getIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Startwind\Inventorio\Collector\System\Security;
4
5
use Startwind\Inventorio\Collector\Collector;
6
7
class AuthorizedKeysCollector implements Collector
8
{
9
    public function getIdentifier(): string
10
    {
11
        return 'SecurityAuthorizedKeys';
12
    }
13
14
    public function collect(): array
15
    {
16
        $results = [];
17
18
        // Read all user accounts from /etc/passwd
19
        $passwdLines = file('/etc/passwd', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
20
21
        foreach ($passwdLines as $line) {
22
            $parts = explode(':', $line);
23
            if (count($parts) < 6) {
24
                continue;
25
            }
26
27
            // Extract username, UID, and home directory
28
            [$username, , $uid, , , $homeDirectory] = array_slice($parts, 0, 6);
29
30
            // Only consider regular users (UID >= 1000) with a valid home directory
31
            if ((int)$uid < 1000 || !is_dir($homeDirectory)) {
32
                continue;
33
            }
34
35
            $authorizedKeysPath = $homeDirectory . '/.ssh/authorized_keys';
36
37
            // If authorized_keys exists, parse it
38
            if (!file_exists($authorizedKeysPath)) {
39
                continue;
40
            }
41
42
            $entries = $this->parseAuthorizedKeysFile($authorizedKeysPath, $username);
43
44
            // Merge entries into the final result list
45
            $results = array_merge($results, $entries);
46
        }
47
48
        return $results;
49
    }
50
51
    /**
52
     * Parse an authorized_keys file and return structured entries including username.
53
     *
54
     * @param string $filePath Path to the authorized_keys file
55
     * @param string $username The user who owns the file
56
     * @return array List of structured authorized key entries
57
     */
58
    private function parseAuthorizedKeysFile(string $filePath, string $username): array
59
    {
60
        $entries = [];
61
62
        $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
63
64
        foreach ($lines as $line) {
65
            $line = trim($line);
66
67
            // Skip comments and empty lines
68
            if ($line === '' || str_starts_with($line, '#')) {
69
                continue;
70
            }
71
72
            // Some lines may include options before the key, like: command="..." ssh-rsa AAAA...
73
            if (preg_match('/^(ssh-(rsa|ed25519|dss)|ecdsa-[^\s]+)\s+([A-Za-z0-9+\/=]+)(\s+(.*))?$/', $line, $matches)) {
74
                $entries[] = [
75
                    'user' => $username,
76
                    'key_type' => $matches[1],
77
                    'key' => $matches[3],
78
                    'comment' => $matches[5] ?? null
79
                ];
80
            }
81
        }
82
83
        return $entries;
84
    }
85
}
86