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

Twitter::authenticate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 4
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
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');
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.php')
96
                    . '?AuthState=' . $stateId . '&force_login=' . strval($this->force_login),
97
            ]
98
        );
99
100
        // First part of OAuth 1.0 authentication is retrieving temporary credentials.
101
        // These identify you as a client to the server.
102
        $temporaryCredentials = $server->getTemporaryCredentials();
103
104
        $state['authtwitter:authdata:requestToken'] = serialize($temporaryCredentials);
105
        Auth\State::saveState($state, self::STAGE_INIT);
106
107
        $server->authorize($temporaryCredentials);
108
        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...
109
    }
110
111
112
    /**
113
     * @param array &$state
114
     * @param \Symfony\Component\HttpFoundation\Request $request
115
     */
116
    public function finalStep(array &$state, Request $request): void
117
    {
118
        $requestToken = unserialize($state['authtwitter:authdata:requestToken']);
119
120
        $oauth_token = $request->get('oauth_token');
121
        if ($oauth_token === null) {
122
            throw new Error\BadRequest("Missing oauth_token parameter.");
123
        }
124
125
        if ($requestToken->getIdentifier() !== $oauth_token) {
126
            throw new Error\BadRequest("Invalid oauth_token parameter.");
127
        }
128
129
        $oauth_verifier = $request->get('oauth_verifier');
130
        if ($oauth_verifier === null) {
131
            throw new Error\BadRequest("Missing oauth_verifier parameter.");
132
        }
133
134
        $server = new TwitterServer(
135
            [
136
                'identifier' => $this->key,
137
                'secret' => $this->secret,
138
            ]
139
        );
140
141
        $tokenCredentials = $server->getTokenCredentials(
142
            $requestToken,
143
            $request->get('oauth_token'),
144
            $request->get('oauth_verifier')
145
        );
146
147
        $state['token_credentials'] = serialize($tokenCredentials);
148
        $userdata = $server->getUserDetails($tokenCredentials);
149
150
        $attributes = [];
151
152
        foreach ($userdata->getIterator() as $key => $value) {
153
            if (is_string($value)) {
154
                $attributes['twitter.' . $key] = [$value];
155
            } else {
156
                // Either the urls or the extra array
157
            }
158
        }
159
160
        foreach ($userdata->urls as $key => $value) {
161
            if (is_string($value)) {
162
                $attributes['twitter.' . $key] = [$value];
163
            } else {
164
                // Something funky.. Maybe the API has changed?
165
            }
166
        }
167
168
        foreach ($userdata->extra as $key => $value) {
169
            if (is_string($value) || is_int($value)) {
170
                $attributes['twitter.' . $key] = [strval($value)];
171
            } else {
172
                // Something funky.. Maybe the API has changed?
173
            }
174
        }
175
176
        $state['Attributes'] = $attributes;
177
    }
178
}
179