Issues (37)

src/Authenticator.php (2 issues)

1
<?php
2
3
namespace SilverStripe\RealMe;
4
5
use Exception;
0 ignored issues
show
This use statement conflicts with another class in this namespace, SilverStripe\RealMe\Exception. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Psr\Log\LoggerInterface;
7
use Psr\SimpleCache\CacheInterface;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Core\Environment;
10
use SilverStripe\Core\Injector\Injectable;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\ORM\ValidationResult;
13
use SilverStripe\RealMe\Authenticator\LoginHandler as RealMeLoginHandler;
14
use SilverStripe\Security\Authenticator as AuthenticatorInterface;
15
use SilverStripe\Security\Member;
16
use SilverStripe\Security\MemberAuthenticator\LogoutHandler;
17
18
/**
19
 * Class RealMeAuthenticator
20
 *
21
 *
22
 */
23
class Authenticator implements AuthenticatorInterface
24
{
25
    use Injectable;
26
27
    private static $dependencies = [
0 ignored issues
show
The private property $dependencies is not used, and could be removed.
Loading history...
28
        'service' => '%$' . RealMeService::class,
29
    ];
30
31
    /**
32
     * @var RealMeService
33
     */
34
    protected $service;
35
36
    /**
37
     * Ensures that enough detail has been configured to allow this authenticator to function properly. Specifically,
38
     * this checks the following:
39
     * - Check certs are in place
40
     * - RealMeSetupTask has been created
41
     *
42
     * @return bool false if the authenticator shouldn't be registered
43
     */
44
    public function __construct()
45
    {
46
        $cache = Injector::inst()->get(CacheInterface::class . '.realMeAuthenticator');
47
48
        $cacheKey = 'RegisterCheck';
49
        if ($cache->get($cacheKey) !== false) {
50
            return true;
51
        }
52
53
        /** @var LoggerInterface $logger */
54
        $logger = Injector::inst()->get(LoggerInterface::class);
55
56
        $certDir = Environment::getEnv('REALME_CERT_DIR');
57
        $certFilename = Environment::getEnv('REALME_SIGNING_CERT_FILENAME');
58
59
        // check we have config constants present.
60
        if (!$certDir) {
61
            $logger->error('RealMe env config REALME_CERT_DIR not set');
62
            return false;
63
        };
64
65
        $path = rtrim($certDir, '/');
66
        if (!file_exists($path) || !is_readable($path)) {
67
            $logger->error('RealMe certificate directory (REALME_CERT_DIR) missing or not readable');
68
            return false;
69
        }
70
71
        // Check certificates (cert dir must exist at this point).
72
        $path = rtrim($certDir, '/') . "/" . $certFilename;
73
        if (!file_exists($path) || !is_readable($path)) {
74
            $logger->error(sprintf('RealMe %s missing: %s', $certFilename, $path));
75
            return false;
76
        }
77
78
        $cache->save('1', $cacheKey);
79
        return true;
80
    }
81
82
    /**
83
     * Returns the services supported by this authenticator
84
     *
85
     * The number should be a bitwise-OR of 1 or more of the following constants:
86
     * Authenticator::LOGIN, Authenticator::LOGOUT, Authenticator::CHANGE_PASSWORD,
87
     * Authenticator::RESET_PASSWORD, or Authenticator::CMS_LOGIN
88
     *
89
     * @return int
90
     */
91
    public function supportedServices()
92
    {
93
        return Authenticator::CMS_LOGIN | Authenticator::LOGIN;
94
    }
95
96
    /**
97
     * Return RequestHandler to manage the log-in process.
98
     *
99
     * The default URL of the RequestHandler should return the initial log-in form, any other
100
     * URL may be added for other steps & processing.
101
     *
102
     * URL-handling methods may return an array [ "Form" => (form-object) ] which can then
103
     * be merged into a default controller.
104
     *
105
     * @param string $link The base link to use for this RequestHandler
106
     * @return RealMeLoginHandler
107
     */
108
    public function getLoginHandler($link)
109
    {
110
        return RealMeLoginHandler::create($link, $this);
111
    }
112
113
    /**
114
     * Return the RequestHandler to manage the log-out process.
115
     *
116
     * The default URL of the RequestHandler should log the user out immediately and destroy the session.
117
     *
118
     * @param string $link The base link to use for this RequestHandler
119
     * @return LogoutHandler
120
     */
121
    public function getLogOutHandler($link)
122
    {
123
        // No-op
124
    }
125
126
    /**
127
     * Return RequestHandler to manage the change-password process.
128
     *
129
     * The default URL of the RequetHandler should return the initial change-password form,
130
     * any other URL may be added for other steps & processing.
131
     *
132
     * URL-handling methods may return an array [ "Form" => (form-object) ] which can then
133
     * be merged into a default controller.
134
     *
135
     * @param string $link The base link to use for this RequestHnadler
136
     */
137
    public function getChangePasswordHandler($link)
138
    {
139
        return null; // Cannot provide change password facilities for RealMe
140
    }
141
142
    /**
143
     * @param string $link
144
     * @return mixed
145
     */
146
    public function getLostPasswordHandler($link)
147
    {
148
        return null; // Cannot provide lost password facilities for RealMe
149
    }
150
151
    /**
152
     * Method to authenticate an user.
153
     *
154
     * @param array $data Raw data to authenticate the user.
155
     * @param HTTPRequest $request
156
     * @param ValidationResult $result A validationresult which is either valid or contains the error message(s)
157
     * @return Member The matched member, or null if the authentication fails
158
     */
159
    public function authenticate(array $data, HTTPRequest $request, ValidationResult &$result = null)
160
    {
161
        try {
162
            $this->service->enforceLogin($request);
163
164
            if ($this->service->getUserData()) {
165
                return $this->service->getUserData()->getMember();
166
            }
167
        } catch (Exception $e) {
168
            $msg = sprintf(
169
                'Error during RealMe authentication process. Code: %d, Message: %s',
170
                $e->getCode(),
171
                $e->getMessage()
172
            );
173
174
            Injector::inst()->get(LoggerInterface::class)->info($msg);
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * Check if the passed password matches the stored one (if the member is not locked out).
182
     *
183
     * Note, we don't return early, to prevent differences in timings to give away if a member
184
     * password is invalid.
185
     *
186
     * Passwords are not part of this authenticator
187
     *
188
     * @param Member $member
189
     * @param string $password
190
     * @param ValidationResult $result
191
     * @return ValidationResult
192
     */
193
    public function checkPassword(Member $member, $password, ValidationResult &$result = null)
194
    {
195
        // No-op
196
    }
197
198
    /**
199
     * @return RealMeService
200
     */
201
    public function getService()
202
    {
203
        return $this->service;
204
    }
205
206
    /**
207
     * @param RealMeService $service
208
     * @return $this
209
     */
210
    public function setService($service)
211
    {
212
        $this->service = $service;
213
214
        return $this;
215
    }
216
}
217