Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
58 / 58
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
UserAuth
100.00% covered (success)
100.00%
58 / 58
100.00% covered (success)
100.00%
6 / 6
22
100.00% covered (success)
100.00%
1 / 1
 getVerifiedUseraccount
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 testPasswordMatching
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getUseraccountByAuthMethod
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 testUseraccountExists
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 getBasicAuth
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
6
 getXAuthKey
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3namespace BO\Zmsbackend\Helper;
4
5use BO\Slim\Render;
6use BO\Zmsbackend\Useraccount\Service\Useraccount;
7
8class UserAuth
9{
10     /**
11     * Get existing useraccount entity with verified password hash
12     *
13     * @return array $useraccount
14    */
15    public static function getVerifiedUseraccount($entity)
16    {
17        $useraccountQuery = new \BO\Zmsbackend\Useraccount\Service\Useraccount();
18        $useraccount = $useraccountQuery->readEntity($entity->getId());
19        // TODO: Remove the password fields when password authentication is removed in the future
20        $originalPassword = $useraccount->password;
21        $useraccount = $useraccount->withVerifiedHash($entity->password);
22        // Only write if password was actually updated (rehashing needed) for system users
23        if ($useraccount->password !== $originalPassword) {
24            $useraccount = $useraccountQuery->writeUpdatedEntity($useraccount->getId(), $useraccount);
25        }
26        return $useraccount;
27    }
28
29    /**
30     * @return true
31     */
32    public static function testPasswordMatching($useraccount, $password): bool
33    {
34        // Do you have old, turbo-legacy, non-crypt hashes?
35        // TODO: Remove the password fields when password authentication is removed in the future
36        $result = (strpos($useraccount->password, '$') !== 0) ?
37            ($useraccount->password === md5($password)) :
38            password_verify($password, $useraccount->password);
39        if (! $result) {
40            $exception = new \BO\Zmsbackend\Useraccount\Exception\InvalidCredentials();
41            $exception->data['password']['messages'] = [
42                'Der Nutzername und das Passwort passen nicht zusammen'
43            ];
44            throw $exception;
45        }
46        return true;
47    }
48
49
50    /**
51     * Get useraccount entity by http basic auth or XAuthKey
52     *
53     * @return array $useraccount
54    */
55    public static function getUseraccountByAuthMethod($request)
56    {
57        $useraccount = null;
58        $basicAuth = static::getBasicAuth($request);
59        $xAuthKey = static::getXAuthKey($request);
60        $useraccountQuery = new \BO\Zmsbackend\Useraccount\Service\Useraccount();
61
62        // TODO: Remove the password fields when password authentication is removed in the future
63        if ($basicAuth && static::testUseraccountExists($basicAuth['username'])) {
64            $useraccount = $useraccountQuery->readEntity($basicAuth['username']);
65            $originalPassword = $useraccount->password;
66            $useraccount = $useraccount->withVerifiedHash($basicAuth['password']);
67            static::testPasswordMatching($useraccount, $basicAuth['password']);
68            // Only write if password was actually updated (rehashing needed) for system users
69            if ($useraccount->password !== $originalPassword) {
70                $useraccount = $useraccountQuery->writeUpdatedEntity($useraccount->getId(), $useraccount);
71            }
72        } elseif ($xAuthKey) {
73            $useraccount = $useraccountQuery->readEntityByAuthKey($xAuthKey);
74        }
75
76        return $useraccount;
77    }
78
79    /**
80     * Test if useraccount exists in db
81     *
82     * @return void
83     */
84    public static function testUseraccountExists($loginName, $password = false)
85    {
86        $query = new \BO\Zmsbackend\Useraccount\Service\Useraccount();
87        if (! $query->readIsUserExisting($loginName, $password)) {
88            $exception = new \BO\Zmsbackend\Useraccount\Exception\InvalidCredentials();
89            $exception->data['password']['messages'] = [
90                'Der Nutzername oder das Passwort wurden falsch eingegeben'
91            ];
92            throw $exception;
93        }
94        return true;
95    }
96
97    /**
98     * Get Basic Authorization header content.
99     *
100     * @return array $authorization
101     */
102    private static function getBasicAuth($request)
103    {
104        $header = $request->getHeaderLine('Authorization');
105        if (strpos($header, 'Basic') !== 0) {
106            return false;
107        }
108        $header = explode(':', base64_decode(substr($header, 6)), 2);
109        $authorization = [
110            'username' => $header[0],
111            'password' => isset($header[1]) ? $header[1] : null,
112        ];
113        $userInfo = explode(':', $request->getUri()->getUserInfo());
114        $userInfo = [
115            'username' => $userInfo[0],
116            'password' => isset($userInfo[1]) ? $userInfo[1] : null
117        ];
118        return (! $authorization || $authorization['password'] !== $userInfo['password']) ? false : $authorization;
119    }
120
121    /**
122     * Get XAuthKey from header
123     * Falls back to X-AuthKey cookie if header is not present
124     *
125     * @return array $useraccount
126    */
127    private static function getXAuthKey($request)
128    {
129        $xAuthKey = $request->getHeaderLine('X-AuthKey');
130        if (! $xAuthKey) {
131            $cookies = $request->getCookieParams();
132            $xAuthKey = (array_key_exists('X-AuthKey', $cookies)) ? $cookies['X-AuthKey'] : null;
133        }
134        return ($xAuthKey) ? $xAuthKey : false;
135    }
136}