Login::setInputs()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Sludio\HelperBundle\Openid\Login;
4
5
use Sludio\HelperBundle\DependencyInjection\ProviderFactory;
6
use Sludio\HelperBundle\Openid\Component\Loginable;
7
use Sludio\HelperBundle\Script\Security\Exception\ErrorException;
8
use Symfony\Component\DependencyInjection\ContainerInterface;
9
use Symfony\Component\HttpFoundation\RedirectResponse;
10
use Symfony\Component\HttpFoundation\RequestStack;
11
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
12
use Sludio\HelperBundle\Script\Utils\Helper;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
15
16
class Login implements Loginable
17
{
18
    use ContainerAwareTrait;
19
20
    /**
21
     * @var RequestStack
22
     */
23
    public $requestStack;
24
25
    /**
26
     * @var Request
27
     */
28
    protected $request;
29
30
    /**
31
     * @var UrlGeneratorInterface
32
     */
33
    protected $generator;
34
35
    protected $redirectRoute;
36
    protected $redirectRouteParams = [];
37
    protected $clientName;
38
39
    protected $apiKey;
40
    protected $openidUrl;
41
    protected $pregCheck;
42
    protected $profileUrl = false;
43
    protected $nsMode = 'auth';
44
    protected $sregFields = 'email';
45
    protected $userClass;
46
    protected $fields = [];
47
48
    public function __construct($clientName, RequestStack $requestStack, UrlGeneratorInterface $generator)
49
    {
50
        $this->request = $requestStack->getCurrentRequest();
51
        $this->requestStack = $requestStack;
52
        $this->generator = $generator;
53
        $this->clientName = $clientName;
54
    }
55
56
    public function makeParameters()
57
    {
58
        $this->setInputs($this->clientName);
59
        $this->nsMode = $this->container->getParameter($this->clientName.'.option.ns_mode') ?: $this->nsMode;
60
        $this->setParameters($this->clientName);
61
62
        if (!empty($this->fields) && \is_array($this->fields)) {
63
            $this->sregFields = implode(',', $this->fields);
64
        }
65
    }
66
67
    private function setInputs($clientName)
68
    {
69
        $inputs = [
70
            'apiKey' => $clientName.'.api_key',
71
            'openidUrl' => $clientName.'.openid_url',
72
            'pregCheck' => $clientName.'.preg_check',
73
            'userClass' => $clientName.'.user_class',
74
        ];
75
76
        foreach ($inputs as $key => $input) {
77
            $this->{$key} = $this->container->getParameter($input);
78
        }
79
    }
80
81
    private function setParameters($clientName)
82
    {
83
        $parameters = [
84
            'profileUrl' => $clientName.'.option.profile_url',
85
            'redirectRoute' => $clientName.'.redirect_route',
86
            'redirectRouteParams' => $clientName.'.option.params',
87
            'fields' => $clientName.'.option.sreg_fields',
88
        ];
89
90
        foreach ($parameters as $key => $param) {
91
            if ($this->container->hasParameter($param)) {
92
                $this->{$key} = $this->container->getParameter($param);
93
            }
94
        }
95
    }
96
97
    /**
98
     * Validates a given URL, ensuring it contains the http or https URI Scheme.
99
     *
100
     * @param string $url
101
     *
102
     * @return bool
103
     */
104
    private function validateUrl($url)
105
    {
106
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
107
            return false;
108
        }
109
110
        return true;
111
    }
112
113
    private function getParams($return, $realm)
114
    {
115
        $params = [
116
            'openid.ns' => 'http://specs.openid.net/auth/2.0',
117
            'openid.mode' => 'checkid_setup',
118
            'openid.return_to' => $return,
119
            'openid.realm' => $realm,
120
            'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select',
121
            'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select',
122
        ];
123
124
        if ($this->nsMode === 'sreg') {
125
            $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
126
            $params['openid.sreg.required'] = $this->sregFields;
127
        }
128
129
        return $params;
130
    }
131
132
    /**
133
     * Build the OpenID login URL.
134
     *
135
     * @param string      $return A custom return to URL
136
     *
137
     * @param string|null $altRealm
138
     *
139
     * @return string
140
     * @throws ErrorException
141
     */
142
    public function urlPath($return = null, $altRealm = null) //HTTP_X_FORWARDED_PROTO
143
    {
144
        $realm = $altRealm ?: Helper::getSchema($this->request).$this->request->server->get('HTTP_HOST');
145
146
        if (null !== $return) {
147
            if (!$this->validateUrl($return)) {
148
                throw new ErrorException('error_oauth_invalid_return_url');
149
            }
150
        } else {
151
            $return = $realm.$this->request->server->get('SCRIPT_NAME');
152
        }
153
154
        return $this->openidUrl.'/'.$this->apiKey.'/?'.http_build_query($this->getParams($return, $realm));
155
    }
156
157
    /**
158
     * Validates a OpenID login request and returns the users OpenID.
159
     *
160
     * @param int $timeout
161
     *
162
     * @return string|null
163
     */
164
    public function validate($timeout = 30)
165
    {
166
        $get = $this->request->query->all();
167
168
        $params = [
169
            'openid.assoc_handle' => $get['openid_assoc_handle'],
170
            'openid.signed' => $get['openid_signed'],
171
            'openid.sig' => $get['openid_sig'],
172
            'openid.ns' => 'http://specs.openid.net/auth/2.0',
173
        ];
174
175
        $signed = explode(',', $get['openid_signed']);
176
177
        foreach ($signed as $item) {
178
            $val = $get['openid_'.str_replace('.', '_', $item)];
179
            $params['openid.'.$item] = get_magic_quotes_gpc() ? stripslashes($val) : $val;
180
        }
181
182
        $params['openid.mode'] = 'check_authentication';
183
        $data = http_build_query($params);
184
185
        $context = stream_context_create([
186
            'http' => [
187
                'method' => 'POST',
188
                'header' => "Accept-language: en\r\n"."Content-type: application/x-www-form-urlencoded\r\n".'Content-Length: '.\strlen($data)."\r\n",
189
                'content' => $data,
190
                'timeout' => $timeout,
191
            ],
192
        ]);
193
194
        preg_match($this->pregCheck, urldecode($get['openid_claimed_id']), $matches);
195
        $openID = (\is_array($matches) && isset($matches[1])) ? $matches[1] : null;
196
197
        return preg_match("#is_valid\s*:\s*true#i", file_get_contents($this->openidUrl.'/'.$this->apiKey, false, $context)) === 1 ? $openID : null;
198
    }
199
200
    private function getData($openID = null)
201
    {
202
        if ($openID) {
203
            $data = file_get_contents($this->profileUrl.$openID);
204
            $json = json_decode($data, true);
205
206
            return new $this->userClass($json['response'], $openID);
207
        }
208
209
        return null;
210
    }
211
212
    public function fetchUser()
213
    {
214
        $user = $this->validate();
215
        if ($user !== null) {
216
            if ($this->profileUrl === false) {
217
                $user = new $this->userClass($this->request->query->all(), $user);
218
            } else {
219
                $user = $this->getData($user);
220
            }
221
        }
222
223
        if ($user === null) {
224
            throw new ErrorException('error_oauth_login_invalid_or_timed_out');
225
        }
226
227
        return $user;
228
    }
229
230
    public function redirect(array $scopes = [], array $options = [], $state = null)
231
    {
232
        if($state) {
233
            $this->redirectRouteParams['token'] = $state;
234
        }
235
        $providerFactory = new ProviderFactory($this->generator, $this->requestStack);
236
        $redirectUri = $providerFactory->generateUrl($this->redirectRoute, $this->redirectRouteParams);
237
238
        return new RedirectResponse($this->urlPath($redirectUri));
239
    }
240
}
241