AbstractProvider   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 6
dl 0
loc 146
ccs 0
cts 60
cp 0
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
getOpenIdUrl() 0 1 ?
A makeAuthUrlV2() 0 14 2
A discover() 0 37 4
A makeAuthUrl() 0 6 1
A parseUserIdFromIdentity() 0 4 1
A getAccessTokenByRequestParameters() 0 40 3
1
<?php
2
/**
3
 * SocialConnect project
4
 * @author: Patsura Dmitry https://github.com/ovr <[email protected]>
5
 */
6
declare(strict_types=1);
7
8
namespace SocialConnect\OpenID;
9
10
use SocialConnect\Provider\AbstractBaseProvider;
11
use SocialConnect\Provider\Exception\InvalidAccessToken;
12
use SocialConnect\Provider\Exception\InvalidResponse;
13
use SocialConnect\Common\Http\Client\Client;
14
15
abstract class AbstractProvider extends AbstractBaseProvider
16
{
17
    /**
18
     * @return string
19
     */
20
    abstract public function getOpenIdUrl();
21
22
    /**
23
     * @var int
24
     */
25
    protected $version;
26
27
    /**
28
     * @var string
29
     */
30
    protected $loginEntrypoint;
31
32
    /**
33
     * @param bool $immediate
34
     * @return string
35
     */
36
    protected function makeAuthUrlV2($immediate)
37
    {
38
        $params = [
39
            'openid.ns' => 'http://specs.openid.net/auth/2.0',
40
            'openid.mode' => $immediate ? 'checkid_immediate' : 'checkid_setup',
41
            'openid.return_to' => $this->getRedirectUrl(),
42
            'openid.realm' => $this->getRedirectUrl()
43
        ];
44
45
        $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
46
        $params['openid.identity'] = $params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
47
48
        return $this->loginEntrypoint . '?' . http_build_query($params, '', '&');
49
    }
50
51
    /**
52
     * @param string $url
53
     * @return string
54
     * @throws InvalidResponse
55
     */
56
    protected function discover($url)
57
    {
58
        $response = $this->httpClient->request(
59
            $url,
60
            [],
61
            Client::GET
62
        );
63
64
        if (!$response->isSuccess()) {
65
            throw new InvalidResponse(
66
                'API response with error code',
67
                $response
68
            );
69
        }
70
71
        if (!$response->hasHeader('Content-Type')) {
72
            throw new InvalidResponse(
73
                'Unknown Content-Type',
74
                $response
75
            );
76
        }
77
78
        $contentType = $response->getHeader('Content-Type');
79
        if (strpos($contentType, 'application/xrds+xml;charset=utf-8') === false) {
80
            throw new InvalidResponse(
81
                'Unexpected Content-Type',
82
                $response
83
            );
84
        }
85
86
        $xml = new \SimpleXMLElement($response->getBody());
87
88
        $this->version = 2;
89
        $this->loginEntrypoint = $xml->XRD->Service->URI;
90
91
        return $this->getOpenIdUrl();
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function makeAuthUrl(): string
98
    {
99
        $this->discover($this->getOpenIdUrl());
100
101
        return $this->makeAuthUrlV2(false);
102
    }
103
104
    /**
105
     * @param string $identity
106
     * @return int
107
     */
108
    protected function parseUserIdFromIdentity($identity)
109
    {
110
        return null;
111
    }
112
113
    /**
114
     * @link http://openid.net/specs/openid-authentication-2_0.html#verification
115
     *
116
     * @param $requestParameters
117
     * @return AccessToken
118
     * @throws InvalidAccessToken
119
     */
120
    public function getAccessTokenByRequestParameters(array $requestParameters)
121
    {
122
        $params = [
123
            'openid.assoc_handle' => $requestParameters['openid_assoc_handle'],
124
            'openid.signed' => $requestParameters['openid_signed'],
125
            'openid.sig' => $requestParameters['openid_sig'],
126
            'openid.ns' => $requestParameters['openid_ns'],
127
            'openid.op_endpoint' => $requestParameters['openid_op_endpoint'],
128
            'openid.claimed_id' => $requestParameters['openid_claimed_id'],
129
            'openid.identity' => $requestParameters['openid_identity'],
130
            'openid.return_to' => $this->getRedirectUrl(),
131
            'openid.response_nonce' => $requestParameters['openid_response_nonce'],
132
            'openid.mode' => 'check_authentication'
133
        ];
134
135
        if (isset($requestParameters['openid_claimed_id'])) {
136
            $claimedId = $requestParameters['openid_claimed_id'];
137
        } else {
138
            $claimedId = $requestParameters['openid_identity'];
139
        }
140
141
        $this->discover($claimedId);
142
143
        $response = $this->httpClient->request(
144
            $this->loginEntrypoint,
145
            $params,
146
            Client::POST
147
        );
148
149
        if (preg_match('/is_valid\s*:\s*true/i', $response->getBody())) {
150
            return new AccessToken(
151
                $requestParameters['openid_identity'],
152
                $this->parseUserIdFromIdentity(
153
                    $requestParameters['openid_identity']
154
                )
155
            );
156
        }
157
158
        throw new InvalidAccessToken;
159
    }
160
}
161