Completed
Push — master ( 89670e...896e52 )
by Jacob
02:12
created

BaseGuard::getRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Canis.io
4
 * @license   MIT
5
 */
6
namespace Canis\Lumen\Jwt;
7
8
use Auth;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Str;
11
use Illuminate\Auth\GuardHelpers;
12
use Illuminate\Contracts\Auth\UserProvider;
13
use Illuminate\Contracts\Auth\Guard as GaurdContract;
14
use Illuminate\Contracts\Auth\Authenticatable;
15
use Canis\Lumen\Jwt\Exceptions\InvalidTokenException;
16
use Canis\Lumen\Jwt\Exceptions\InvalidAdapterException;
17
use Canis\Lumen\Jwt\Contracts\AdapterFactory as AdapterFactoryContract;
18
use Canis\Lumen\Jwt\Contracts\Generator as GeneratorContract;
19
use Canis\Lumen\Jwt\Contracts\Processor as ProcessorContract;
20
21
abstract class BaseGuard
22
    implements GaurdContract, GuardInterface
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
23
{
24
    use GuardHelpers;
25
26
    /**
27
     * @var Request
28
     */
29
    protected $request;
30
31
    /**
32
     * Constructor
33
     * 
34
     * @param UserProvider $provider
35
     * @param Request      $request
36
     */
37 13
    public function __construct(UserProvider $provider, Request $request)
38
    {
39 13
        $this->request = $request;
40 13
        $this->provider = $provider;
41 13
    }
42
43
    /**
44
     * Returns the adapter class name to use
45
     * 
46
     * @return string
47
     */
48 7
    public function getAdapterFactoryClass()
49
    {
50 7
        $config = config('jwt');
51 7
        if (!isset($config['adapter'])) {
52 5
            $config['adapter'] = 'lcobucci';
53 5
        }
54 7
        if (class_exists($config['adapter'])) {
55 1
            $factoryClass = $config['adapter'];
56 1
        } else {
57 6
            $factoryClass = 'Canis\Lumen\Jwt\Adapters\\' . ucfirst($config['adapter']) .'\Factory';
58 6
            if (!class_exists($factoryClass)) {
59 1
                throw new InvalidAdapterException("{$config['adapter']} is not available");
60
            }
61
        }
62 6
        return $factoryClass;
63
    }
64
65
    /**
66
     * Returns the adapter factory object
67
     * 
68
     * @return AdapterFactoryContract
69
     */
70 7
    protected function getAdapterFactory()
71
    {
72 7
        static $factory;
73 7
        if (!isset($factory)) {
74 7
            $config = config('jwt');
75 7
            $factoryClass = $this->getAdapterFactoryClass();
76 6
            $factory = new $factoryClass($config);
77 6
        }
78 6
        return $factory;
79
    }
80
81
    /**
82
     * Returns a token processor from the adapter factory
83
     * 
84
     * @return ProcessorContract
85
     */
86 3
    protected function getProcessor()
87
    {
88 3
        return $this->getAdapterFactory()->getProcessor();
89
    }
90
91
    /**
92
     * Returns a token generator from the adapter factory
93
     * 
94
     * @return GeneratorCotnract
95
     */
96 5
    protected function getGenerator()
97
    {
98 5
        return $this->getAdapterFactory()->getGenerator();
99
    }
100
101
    /**
102
     * Gets the provider
103
     * 
104
     * @return UserProvider
105
     */
106 6
    public function getProvider()
107
    {
108 6
        return $this->provider;
109
    }
110
111
    /**
112
     * @inheritdoc
113
     */
114 1
    public function user()
115
    {
116 1
        if (!is_null($this->user)) {
117 1
            return $this->user;
118
        }
119 1
        $user = null;
120 1
        $token = $this->getBearerToken();
121 1
        if ($token !== false) {
122 1
            $user = $this->getProvider()->retrieveById($token->getClaim('sub'));
123 1
        }
124 1
        return $this->user = $user;
125
    }
126
127
    /**
128
     * Get's the bearer token from the request header
129
     * 
130
     * @return Token
131
     */
132 4
    public function getBearerToken()
133
    {
134 4
        $authHeader = $this->request->headers->get('Authorization');
135 4
        if (empty($authHeader)) {
136 1
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Canis\Lumen\Jwt\BaseGuard::getBearerToken of type Canis\Lumen\Jwt\Token.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
137
        }
138 3
        if (!Str::startsWith(strtolower($authHeader), 'bearer')) {
139 1
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Canis\Lumen\Jwt\BaseGuard::getBearerToken of type Canis\Lumen\Jwt\Token.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
140
        }
141 2
        $token = trim(str_ireplace('bearer', '', $authHeader));
142 2
        $processor = $this->getProcessor();
143 2
        return $processor($token);
144
    }
145
146
    /**
147
     * @inheritdoc
148
     */
149 2
    public function validate(array $credentials = [])
150
    {
151 2
        $user = $this->getProvider()->retrieveByCredentials($credentials);
152 2
        if ($this->hasValidCredentials($user, $credentials)) {
153 1
            return true;
154
        }
155 1
        return false;
156
    }
157
158
    /**
159
     * Determine if the user matches the credentials.
160
     *
161
     * @param  mixed  $user
162
     * @param  array  $credentials
163
     * @return bool
164
     */
165 5
    protected function hasValidCredentials($user, $credentials)
166
    {
167 5
        return !is_null($user) && $this->getProvider()->validateCredentials($user, $credentials);
168
    }
169
170
    /**
171
     * Sets the Request
172
     * 
173
     * @param Request $request
174
     */
175 1
    public function setRequest(Request $request)
176
    {
177 1
        $this->request = $request;
178 1
    }
179
180
    /**
181
     * Gets the request
182
     * 
183
     * @return Request
184
     */
185 1
    public function getRequest()
186
    {
187 1
        return $this->request;
188
    }
189
190
    /**
191
     * Attempt to authenticate a user using the given credentials.
192
     *
193
     * @param  array  $credentials
194
     * @return bool|string
195
     */
196 3
    public function attempt(array $credentials = [])
197
    {
198 3
        $user = $this->getProvider()->retrieveByCredentials($credentials);
199 3
        if ($this->hasValidCredentials($user, $credentials)) {
200 2
            $tokenGenerator = $this->getGenerator();
201 2
            $claims = $user->getJWTClaims();
0 ignored issues
show
Bug introduced by
The method getJWTClaims() does not seem to exist on object<Illuminate\Contracts\Auth\Authenticatable>.

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...
202 2
            $claims['sub'] = $user->getJWTSubject();
0 ignored issues
show
Bug introduced by
The method getJWTSubject() does not seem to exist on object<Illuminate\Contracts\Auth\Authenticatable>.

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...
203 2
            $claims['type'] = $user->getJWTSubjectType();
0 ignored issues
show
Bug introduced by
The method getJWTSubjectType() does not seem to exist on object<Illuminate\Contracts\Auth\Authenticatable>.

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...
204 2
            if (!($token = $tokenGenerator($claims))) {
205 1
                throw new InvalidTokenException("Unable to generate token");
206
            }
207 1
            return $token;
208
        }
209 1
        return false;
210
    }
211
}
212