Passed
Push — master ( d8cead...33fe5f )
by Tim
05:01 queued 11s
created

BearerAuthenticator::getCredentials()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * AppserverIo\Authenticator\BearerAuthenticator
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2016 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/authenticator
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Authenticator;
22
23
use AppserverIo\Lang\String;
24
use AppserverIo\Psr\Auth\RealmInterface;
25
use AppserverIo\Psr\HttpMessage\Protocol;
26
use AppserverIo\Psr\Security\PrincipalInterface;
27
use AppserverIo\Psr\Servlet\Utils\RequestHandlerKeys;
28
use AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface;
29
use AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface;
30
31
/**
32
 * A bearer token based authenticator implementation.
33
 *
34
 * @author    Tim Wagner <[email protected]>
35
 * @copyright 2016 TechDivision GmbH <[email protected]>
36
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
37
 * @link      https://github.com/appserver-io/authenticator
38
 * @link      http://www.appserver.io
39
 */
40
class BearerAuthenticator extends AbstractAuthenticator
41
{
42
43
    /**
44
     * Defines the auth type which should match the client request type definition
45
     *
46
     * @var string AUTH_TYPE
47
     */
48
    const AUTH_TYPE = 'Bearer';
49
50
    /**
51
     * Returns the parsed password.
52
     *
53
     * @return \AppserverIo\Lang\String The password
54
     */
55
    public function getPassword()
56
    {
57
        return new String();
58
    }
59
60
    /**
61
     * Return's the array with the login credentials.
62
     *
63
     * @return \AppserverIo\Lang\String[] The array with the login credentials
64
     */
65
    protected function getCredentials()
66
    {
67
        return array($this->getUsername(), $this->getPassword());
0 ignored issues
show
Bug Best Practice introduced by
The expression return array($this->getU..., $this->getPassword()) returns an array which contains values of type string which are incompatible with the documented value type AppserverIo\Lang\String.
Loading history...
68
    }
69
70
    /**
71
     * Try to authenticate the user making this request, based on the specified login configuration.
72
     *
73
     * Return TRUE if any specified constraint has been satisfied, or FALSE if we have created a response
74
     * challenge already.
75
     *
76
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
77
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
78
     *
79
     * @return boolean TRUE if authentication has already been processed on a request before, else FALSE
80
     * @throws \AppserverIo\Http\Authentication\AuthenticationException Is thrown if the request can't be authenticated
81
     */
82
    public function authenticate(HttpServletRequestInterface $servletRequest, HttpServletResponseInterface $servletResponse)
83
    {
84
85
        // invoke the onCredentials callback to load the credentials from the request
86
        $this->onCredentials($servletRequest, $servletResponse);
87
88
        // load the realm to authenticate this request for
89
        /** @var AppserverIo\Appserver\ServletEngine\Security\RealmInterface $realm */
90
        $realm = $this->getAuthenticationManager()->getRealm($this->getRealmName());
91
92
        // authenticate the request and initialize the user principal
93
        $userPrincipal = call_user_func_array(array($realm, 'authenticate'), $this->getCredentials());
94
95
        // query whether or not the realm returned an authenticated user principal
96
        if ($userPrincipal == null) {
97
            // invoke the onFailure callback and forward the user to the error page
98
            $this->onFailure($realm, $servletRequest, $servletResponse);
99
            return false;
100
        }
101
102
        // invoke the onSuccess callback and redirect the user to the original page
103
        $this->onSuccess($userPrincipal, $servletRequest, $servletResponse);
104
        return false;
105
    }
106
107
    /**
108
     * Will be invoked to load the credentials from the request.
109
     *
110
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
111
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
112
     *
113
     * @return void
114
     */
115
    protected function onCredentials(
116
        HttpServletRequestInterface $servletRequest,
117
        HttpServletResponseInterface $servletResponse
118
    ) {
119
120
        // try to load the access token from the request instead
121
        if ($servletRequest->hasHeader(Protocol::HEADER_AUTHORIZATION)) {
122
            // extract the access token from the authorization header
123
            sscanf($servletRequest->getHeader(Protocol::HEADER_AUTHORIZATION), 'Bearer %s', $accessToken);
0 ignored issues
show
Bug introduced by
It seems like $servletRequest->getHead...::HEADER_AUTHORIZATION) can also be of type null; however, parameter $string of sscanf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
            sscanf(/** @scrutinizer ignore-type */ $servletRequest->getHeader(Protocol::HEADER_AUTHORIZATION), 'Bearer %s', $accessToken);
Loading history...
124
            $this->username = new String($accessToken);
125
        }
126
    }
127
128
    /**
129
     * Will be invoked when login fails for some reasons.
130
     *
131
     * @param \AppserverIo\Appserver\ServletEngine\Security\RealmInterface $realm           The realm instance containing the exception stack
0 ignored issues
show
Bug introduced by
The type AppserverIo\Appserver\Se...Security\RealmInterface 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...
132
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface    $servletRequest  The servlet request instance
133
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface   $servletResponse The servlet response instance
134
     *
135
     * @return void
136
     */
137
    protected function onFailure(
138
        RealmInterface $realm,
139
        HttpServletRequestInterface $servletRequest,
140
        HttpServletResponseInterface $servletResponse
141
    ) {
142
        $this->forwardToErrorPage($servletRequest, $servletResponse);
143
    }
144
145
    /**
146
     * Will be invoked on a successfull login.
147
     *
148
     * @param \AppserverIo\Psr\Security\PrincipalInterface               $userPrincipal   The user principal logged into the system
149
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
150
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
151
     *
152
     * @return void
153
     */
154
    protected function onSuccess(
155
        PrincipalInterface $userPrincipal,
156
        HttpServletRequestInterface $servletRequest,
157
        HttpServletResponseInterface $servletResponse
158
    ) {
159
160
        // add the user principal and the authentication type to the request
161
        $this->register($servletRequest, $servletResponse, $userPrincipal);
162
    }
163
164
    /**
165
     * Register's the user principal and the authenticytion in the request and session.
166
     *
167
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
168
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
169
     * @param \AppserverIo\Psr\Security\PrincipalInterface               $userPrincipal   The actual user principal
170
     *
171
     * @return void
172
     */
173
    protected function register(
174
        HttpServletRequestInterface $servletRequest,
175
        HttpServletResponseInterface $servletResponse,
176
        PrincipalInterface $userPrincipal
177
    ) {
178
179
        // add the user principal and the authentication type to the request
180
        $servletRequest->setUserPrincipal($userPrincipal);
0 ignored issues
show
Bug introduced by
The method setUserPrincipal() does not exist on AppserverIo\Psr\Servlet\...ServletRequestInterface. It seems like you code against a sub-type of AppserverIo\Psr\Servlet\...ServletRequestInterface such as AppserverIo\Authenticato...ServletRequestInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

180
        $servletRequest->/** @scrutinizer ignore-call */ 
181
                         setUserPrincipal($userPrincipal);
Loading history...
181
        $servletRequest->setAuthType($this->getAuthType());
0 ignored issues
show
Bug introduced by
The method setAuthType() does not exist on AppserverIo\Psr\Servlet\...ServletRequestInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

181
        $servletRequest->/** @scrutinizer ignore-call */ 
182
                         setAuthType($this->getAuthType());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
182
    }
183
184
    /**
185
     * Forward's the request to the configured login page.
186
     *
187
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
188
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
189
     *
190
     * @return void
191
     */
192
    protected function forwardToLoginPage(
193
        HttpServletRequestInterface $servletRequest,
194
        HttpServletResponseInterface $servletResponse
195
    ) {
196
        $servletRequest->setDispatched(true);
197
        $servletResponse->setHeaders($this->getDefaultHeaders());
198
        $servletResponse->appendBodyStream($this->serialize(array('error' => 'Use SSO server to aquire a valid access token')));
199
        $servletResponse->setStatusCode(500);
200
    }
201
202
    /**
203
     * Forward's the request to the configured error page.
204
     *
205
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface  $servletRequest  The servlet request instance
206
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletResponseInterface $servletResponse The servlet response instance
207
     *
208
     * @return void
209
     */
210
    protected function forwardToErrorPage(
211
        HttpServletRequestInterface $servletRequest,
212
        HttpServletResponseInterface $servletResponse
213
    ) {
214
        $servletRequest->setDispatched(true);
215
        $servletResponse->setHeaders($this->getDefaultHeaders());
216
        $servletResponse->appendBodyStream($this->serialize(array('error' => 'You need an valid access token to use the API')));
217
        $servletResponse->setStatusCode(401);
218
    }
219
220
    /**
221
     * Return's the default headers to set.
222
     *
223
     * @return string[] The array with the headers
224
     */
225
    protected function getDefaultHeaders()
226
    {
227
        return array(Protocol::HEADER_CONTENT_TYPE => 'application/json');
0 ignored issues
show
Bug Best Practice introduced by
The expression return array(AppserverIo... => 'application/json') returns the type array<string,string> which is incompatible with the documented return type AppserverIo\Lang\String[].
Loading history...
228
    }
229
230
    /**
231
     * Serialize's the passed value an return's it.
232
     *
233
     * @param mixed $value The value that has to be serialized
234
     *
235
     * @return string The serialized value
236
     */
237
    protected function serialize($value)
238
    {
239
        return json_encode($value);
0 ignored issues
show
Bug Best Practice introduced by
The expression return json_encode($value) returns the type string which is incompatible with the documented return type AppserverIo\Lang\String.
Loading history...
240
    }
241
242
    /**
243
     * Tries the login the passed username/password combination for the login configuration.
244
     *
245
     * @param \AppserverIo\Lang\String                                  $username       The username used to login
246
     * @param \AppserverIo\Lang\String                                  $password       The password used to authenticate the user
247
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface $servletRequest The servlet request instance
248
     *
249
     * @return \AppserverIo\Psr\Security\PrincipalInterface The authenticated user principal
250
     */
251
    public function login(
252
        String $username,
253
        String $password,
254
        HttpServletRequestInterface $servletRequest
255
    ) {
256
257
        // load the realm to authenticate this request for
258
        /** @var AppserverIo\Appserver\ServletEngine\Security\RealmInterface $realm */
259
        $realm = $this->getAuthenticationManager()->getRealm($this->getRealmName());
260
261
        // authenticate the request and initialize the user principal
262
        $userPrincipal = call_user_func_array(array($realm, 'authenticate'), array($username, $password));
263
264
        // query whether or not we can authenticate the user
265
        if ($userPrincipal == null) {
266
            throw new ServletException(sprintf('Can\'t authenticate user %s', $username));
0 ignored issues
show
Bug introduced by
The type AppserverIo\Authenticator\ServletException 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...
267
        }
268
269
        // add the user principal and the authentication type to the request
270
        $servletRequest->setUserPrincipal($userPrincipal);
271
        $servletRequest->setAuthType($this->getAuthType());
272
273
        // return's the user principal
274
        return $userPrincipal;
275
    }
276
277
    /**
278
     * Logout the actual user from the session.
279
     *
280
     * @param \AppserverIo\Psr\Servlet\Http\HttpServletRequestInterface $servletRequest The servlet request instance
281
     *
282
     * @return void
283
     */
284
    public function logout(HttpServletRequestInterface $servletRequest)
285
    {
286
    }
287
}
288