Passed
Pull Request — master (#2)
by Tim
02:17
created

Twitter::temporaryCredentials()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 13
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 26
rs 9.8333
1
<?php
2
3
namespace SimpleSAML\Module\authtwitter\Auth\Source;
4
5
use League\OAuth1\Client\Server\Twitter as TwitterServer;
6
use SimpleSAML\Assert\Assert;
7
use SimpleSAML\Auth;
8
use SimpleSAML\Configuration;
9
use SimpleSAML\Error;
10
use SimpleSAML\Logger;
11
use SimpleSAML\Module;
12
use SimpleSAML\Utils;
13
use Symfony\Component\HttpFoundation\Request;
14
15
/**
16
 * Authenticate using Twitter.
17
 *
18
 * @package simplesamlphp/simplesamlphp-module-authtwitter
19
 */
20
21
class Twitter extends Auth\Source
22
{
23
    /**
24
     * The string used to identify our states.
25
     */
26
    public const STAGE_INIT = 'twitter:init';
27
28
    /**
29
     * The key of the AuthId field in the state.
30
     */
31
    public const AUTHID = 'twitter:AuthId';
32
33
    /** @var string */
34
    private string $key;
35
36
    /** @var string */
37
    private string $secret;
38
39
    /** @var string */
40
    private string $scope;
41
42
    /** @var bool */
43
    private bool $force_login;
44
45
    /**
46
     * Constructor for this authentication source.
47
     *
48
     * @param array $info  Information about this authentication source.
49
     * @param array $config  Configuration.
50
     */
51
    public function __construct(array $info, array $config)
52
    {
53
        // Call the parent constructor first, as required by the interface
54
        parent::__construct($info, $config);
55
56
        $configObject = Configuration::loadFromArray(
57
            $config,
58
            'authsources[' . var_export($this->authId, true) . ']'
59
        );
60
61
        $this->key = $configObject->getString('key');
62
        $this->secret = $configObject->getString('secret');
63
        $this->scope = $configObject->getString('scope', null);
64
        $this->force_login = $configObject->getBoolean('force_login', false);
65
    }
66
67
68
    /**
69
     * Log-in using Twitter platform
70
     *
71
     * @param array &$state  Information about the current authentication.
72
     */
73
    public function authenticate(array &$state): void
74
    {
75
        $this->temporaryCredentials($state);
76
    }
77
78
79
    /**
80
     * Retrieve temporary credentials
81
     *
82
     * @param array &$state  Information about the current authentication.
83
     */
84
    private function temporaryCredentials(array &$state): void
85
    {
86
        // We are going to need the authId in order to retrieve this authentication source later
87
        $state[self::AUTHID] = $this->authId;
88
89
        $stateId = base64_encode(Auth\State::saveState($state, self::STAGE_INIT));
90
91
        $server = new TwitterServer(
92
            [
93
                'identifier' => $this->key,
94
                'secret' => $this->secret,
95
                'callback_uri' => Module::getModuleURL('authtwitter/linkback')
96
                    . '?AuthState=' . $stateId . '&force_login=' . strval($this->force_login),
97
                'scope' => $this->scope,
98
            ]
99
        );
100
101
        // First part of OAuth 1.0 authentication is retrieving temporary credentials.
102
        // These identify you as a client to the server.
103
        $temporaryCredentials = $server->getTemporaryCredentials();
104
105
        $state['authtwitter:authdata:requestToken'] = serialize($temporaryCredentials);
106
        Auth\State::saveState($state, self::STAGE_INIT);
107
108
        $server->authorize($temporaryCredentials);
109
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
110
    }
111
112
113
    /**
114
     * @param array &$state
115
     * @param \Symfony\Component\HttpFoundation\Request $request
116
     */
117
    public function finalStep(array &$state, Request $request): void
118
    {
119
        $requestToken = unserialize($state['authtwitter:authdata:requestToken']);
120
121
        $oauth_token = $request->get('oauth_token');
122
        if ($oauth_token === null) {
123
            throw new Error\BadRequest("Missing oauth_token parameter.");
124
        }
125
126
        if ($requestToken->getIdentifier() !== $oauth_token) {
127
            throw new Error\BadRequest("Invalid oauth_token parameter.");
128
        }
129
130
        $oauth_verifier = $request->get('oauth_verifier');
131
        if ($oauth_verifier === null) {
132
            throw new Error\BadRequest("Missing oauth_verifier parameter.");
133
        }
134
135
        $server = new TwitterServer(
136
            [
137
                'identifier' => $this->key,
138
                'secret' => $this->secret,
139
            ]
140
        );
141
142
        $tokenCredentials = $server->getTokenCredentials(
143
            $requestToken,
144
            $request->get('oauth_token'),
145
            $request->get('oauth_verifier')
146
        );
147
148
        $state['token_credentials'] = serialize($tokenCredentials);
149
        $userdata = $server->getUserDetails($tokenCredentials);
150
151
        $attributes = [];
152
153
        foreach ($userdata->getIterator() as $key => $value) {
154
            if (is_string($value)) {
155
                $attributes['twitter.' . $key] = [$value];
156
            } else {
157
                // Either the urls or the extra array
158
            }
159
        }
160
161
        foreach ($userdata->urls as $key => $value) {
162
            if (is_string($value)) {
163
                $attributes['twitter.' . $key] = [$value];
164
            } else {
165
                // Something funky.. Maybe the API has changed?
166
            }
167
        }
168
169
        foreach ($userdata->extra as $key => $value) {
170
            if (is_string($value) || is_int($value)) {
171
                $attributes['twitter.' . $key] = [strval($value)];
172
            } else {
173
                // Something funky.. Maybe the API has changed?
174
            }
175
        }
176
177
        $state['Attributes'] = $attributes;
178
    }
179
}
180