Passed
Pull Request — master (#18)
by
unknown
03:10
created

LaravelSSOServer::checkBrokerUserAuthentication()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 0
1
<?php
2
3
namespace Zefy\LaravelSSO;
4
5
use Illuminate\Database\Eloquent\ModelNotFoundException;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Support\Facades\Cache;
8
use Illuminate\Support\Facades\Session;
9
use Zefy\SimpleSSO\SSOServer;
10
use Zefy\LaravelSSO\Resources\UserResource;
11
use Zefy\SimpleSSO\Exceptions\SSOServerException;
12
13
class LaravelSSOServer extends SSOServer
14
{
15
    /**
16
     * Redirect to provided URL with query string.
17
     *
18
     * If $url is null, redirect to url which given in 'return_url'.
19
     *
20
     * @param string|null $url URL to be redirected.
21
     * @param array $parameters HTTP query string.
22
     * @param int $httpResponseCode HTTP response code for redirection.
23
     *
24
     * @return void
25
     */
26
    protected function redirect(?string $url = null, array $parameters = [], int $httpResponseCode = 307)
27
    {
28
        if (!$url) {
29
            $url = urldecode(request()->get('return_url', null));
30
        }
31
32
        $query = '';
33
        // Making URL query string if parameters given.
34
        if (!empty($parameters)) {
35
            $query = '?';
36
37
            if (parse_url($url, PHP_URL_QUERY)) {
38
                $query = '&';
39
            }
40
41
            $query .= http_build_query($parameters);
42
        }
43
44
        app()->abort($httpResponseCode, '', ['Location' => $url . $query]);
0 ignored issues
show
introduced by
The method abort() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

44
        app()->/** @scrutinizer ignore-call */ abort($httpResponseCode, '', ['Location' => $url . $query]);
Loading history...
45
    }
46
47
    /**
48
     * Returning json response for the broker.
49
     *
50
     * @param null|array $response Response array which will be encoded to json.
51
     * @param int $httpResponseCode HTTP response code.
52
     *
53
     * @return string
54
     */
55
    protected function returnJson(?array $response = null, int $httpResponseCode = 200)
56
    {
57
        return response()->json($response, $httpResponseCode);
58
    }
59
60
    /**
61
     * Authenticate using user credentials
62
     *
63
     * @param string $username
64
     * @param string $password
65
     *
66
     * @return bool
67
     */
68
    protected function authenticate(string $username, string $password)
69
    {
70
        if (!Auth::attempt(['email' => $username, 'password' => $password])) {
71
            return false;
72
        }
73
74
        // After authentication Laravel will change session id, but we need to keep
75
        // this the same because this session id can be already attached to other brokers.
76
        $sessionId = $this->getBrokerSessionId();
77
        $savedSessionId = $this->getBrokerSessionData($sessionId);
0 ignored issues
show
Bug introduced by
It seems like $sessionId can also be of type null; however, parameter $brokerSessionId of Zefy\LaravelSSO\LaravelS...:getBrokerSessionData() 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

77
        $savedSessionId = $this->getBrokerSessionData(/** @scrutinizer ignore-type */ $sessionId);
Loading history...
78
        $this->startSession($savedSessionId);
0 ignored issues
show
Bug introduced by
It seems like $savedSessionId can also be of type null; however, parameter $sessionId of Zefy\LaravelSSO\LaravelSSOServer::startSession() 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

78
        $this->startSession(/** @scrutinizer ignore-type */ $savedSessionId);
Loading history...
79
80
        return true;
81
    }
82
83
    /**
84
     * Get the secret key and other info of a broker
85
     *
86
     * @param string $brokerId
87
     *
88
     * @return null|array
89
     */
90
    protected function getBrokerInfo(string $brokerId)
91
    {
92
        try {
93
            $broker = config('laravel-sso.brokersModel')::where('name', $brokerId)->firstOrFail();
94
        } catch (ModelNotFoundException $e) {
95
            return null;
96
        }
97
98
        return $broker;
99
    }
100
101
    /**
102
     * Check for User Auth with Broker Application.
103
     *
104
     * @return boolean
105
     */
106
    protected function checkBrokerUserAuthentication()
107
    {
108
        $userInfo = $this->userInfo();
109
        $broker = $this->getBrokerDetail();
110
        if(!empty($userInfo->id) && !empty($broker)) {
0 ignored issues
show
Bug introduced by
The property id does not exist on string.
Loading history...
111
            $brokerUser = config('laravel-sso.brokersUserModel')::where('user_id', $userInfo->id)->where('broker_id', $broker->id)->first();
112
            if(empty($brokerUser)) {
113
                return false;
114
            }
115
        }
116
        return true;
117
    }
118
119
    /**
120
     * Check for the User authorization with application and return error or userinfo
121
     *
122
     * @return string
123
     */
124
    public function checkUserApplicationAuth()
125
    {
126
        try {
127
            if(empty($this->checkBrokerUserAuthentication())) {
128
                $this->fail('User authorization failed with application.');
129
            }
130
        } catch (SSOServerException $e) {
131
            return $this->returnJson(['error' => $e->getMessage()]);
132
        }
133
        return $this->userInfo();
134
    }
135
136
    /**
137
     * Returning the broker details
138
     *
139
     * @return string
140
     */
141
    public function getBrokerDetail()
142
    {
143
        return $this->getBrokerInfo($this->brokerId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getBrokerInfo($this->brokerId) also could return the type array which is incompatible with the documented return type string.
Loading history...
144
    }
145
146
    /**
147
     * Get the information about a user
148
     *
149
     * @param string $username
150
     *
151
     * @return array|object|null
152
     */
153
    protected function getUserInfo(string $username)
154
    {
155
        try {
156
            $user = config('laravel-sso.usersModel')::where('email', $username)->firstOrFail();
157
        } catch (ModelNotFoundException $e) {
158
            return null;
159
        }
160
161
        return $user;
162
    }
163
164
    /**
165
     * Returning user info for broker. Should return json or something like that.
166
     *
167
     * @param array|object $user Can be user object or array.
168
     *
169
     * @return array|object|UserResource
170
     */
171
    protected function returnUserInfo($user)
172
    {
173
        return new UserResource($user);
174
    }
175
176
    /**
177
     * Return session id sent from broker.
178
     *
179
     * @return null|string
180
     */
181
    protected function getBrokerSessionId()
182
    {
183
        $authorization = request()->header('Authorization', null);
184
        if ($authorization &&  strpos($authorization, 'Bearer') === 0) {
0 ignored issues
show
Bug introduced by
It seems like $authorization can also be of type array; however, parameter $haystack of strpos() 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

184
        if ($authorization &&  strpos(/** @scrutinizer ignore-type */ $authorization, 'Bearer') === 0) {
Loading history...
185
            return substr($authorization, 7);
0 ignored issues
show
Bug introduced by
It seems like $authorization can also be of type array; however, parameter $string of substr() 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

185
            return substr(/** @scrutinizer ignore-type */ $authorization, 7);
Loading history...
186
        }
187
188
        return null;
189
    }
190
191
    /**
192
     * Start new session when user visits server.
193
     *
194
     * @return void
195
     */
196
    protected function startUserSession()
197
    {
198
        // Session must be started by middleware.
199
    }
200
201
    /**
202
     * Set session data
203
     *
204
     * @param string $key
205
     * @param null|string $value
206
     *
207
     * @return void
208
     */
209
    protected function setSessionData(string $key, ?string $value = null)
210
    {
211
        if (!$value) {
212
            Session::forget($key);
213
            return;
214
        }
215
216
        Session::put($key, $value);
217
    }
218
219
    /**
220
     * Get data saved in session.
221
     *
222
     * @param string $key
223
     *
224
     * @return string
225
     */
226
    protected function getSessionData(string $key)
227
    {
228
        if ($key === 'id') {
229
            return Session::getId();
230
        }
231
232
        return Session::get($key, null);
233
    }
234
235
    /**
236
     * Start new session with specific session id.
237
     *
238
     * @param $sessionId
239
     *
240
     * @return void
241
     */
242
    protected function startSession(string $sessionId)
243
    {
244
        Session::setId($sessionId);
245
        Session::start();
246
    }
247
248
    /**
249
     * Save broker session data to cache.
250
     *
251
     * @param string $brokerSessionId
252
     * @param string $sessionData
253
     *
254
     * @return void
255
     */
256
    protected function saveBrokerSessionData(string $brokerSessionId, string $sessionData)
257
    {
258
        Cache::put('broker_session:' . $brokerSessionId, $sessionData, now()->addHour());
259
    }
260
261
    /**
262
     * Get broker session data from cache.
263
     *
264
     * @param string $brokerSessionId
265
     *
266
     * @return null|string
267
     */
268
    protected function getBrokerSessionData(string $brokerSessionId)
269
    {
270
        return Cache::get('broker_session:' . $brokerSessionId);
271
    }
272
}
273