Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace IMSGlobal\LTI\OAuth;
4
 
5
/**
6
 * Class to represent an %OAuth Server
7
 *
8
 * @copyright  Andy Smith
9
 * @version 2008-08-04
10
 * @license https://opensource.org/licenses/MIT The MIT License
11
 */
12
#[\AllowDynamicProperties]
13
class OAuthServer {
14
 
15
    protected $timestamp_threshold = 300; // in seconds, five minutes
16
    protected $version = '1.0';             // hi blaine
17
    protected $signature_methods = array();
18
 
19
    protected $data_store;
20
 
21
    function __construct($data_store) {
22
        $this->data_store = $data_store;
23
    }
24
 
25
    public function add_signature_method($signature_method) {
26
        $this->signature_methods[$signature_method->get_name()] = $signature_method;
27
    }
28
 
29
    // high level functions
30
 
31
    /**
32
     * process a request_token request
33
     * returns the request token on success
34
     */
35
    public function fetch_request_token(&$request) {
36
 
37
        $this->get_version($request);
38
 
39
        $consumer = $this->get_consumer($request);
40
 
41
        // no token required for the initial token request
42
        $token = NULL;
43
 
44
        $this->check_signature($request, $consumer, $token);
45
 
46
        // Rev A change
47
        $callback = $request->get_parameter('oauth_callback');
48
        $new_token = $this->data_store->new_request_token($consumer, $callback);
49
 
50
        return $new_token;
51
 
52
    }
53
 
54
    /**
55
     * process an access_token request
56
     * returns the access token on success
57
     */
58
    public function fetch_access_token(&$request) {
59
 
60
        $this->get_version($request);
61
 
62
        $consumer = $this->get_consumer($request);
63
 
64
        // requires authorized request token
65
        $token = $this->get_token($request, $consumer, "request");
66
 
67
        $this->check_signature($request, $consumer, $token);
68
 
69
        // Rev A change
70
        $verifier = $request->get_parameter('oauth_verifier');
71
        $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);
72
 
73
        return $new_token;
74
 
75
    }
76
 
77
    /**
78
     * verify an api call, checks all the parameters
79
     */
80
    public function verify_request(&$request) {
81
 
82
        $this->get_version($request);
83
        $consumer = $this->get_consumer($request);
84
        $token = $this->get_token($request, $consumer, "access");
85
        $this->check_signature($request, $consumer, $token);
86
 
87
        return array($consumer, $token);
88
 
89
    }
90
 
91
    // Internals from here
92
    /**
93
     * version 1
94
     */
95
    private function get_version(&$request) {
96
 
97
        $version = $request->get_parameter("oauth_version");
98
        if (!$version) {
99
            // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present.
100
            // Chapter 7.0 ("Accessing Protected Ressources")
101
            $version = '1.0';
102
        }
103
        if ($version !== $this->version) {
104
            throw new OAuthException("OAuth version '$version' not supported");
105
        }
106
 
107
        return $version;
108
 
109
    }
110
 
111
    /**
112
     * figure out the signature with some defaults
113
     */
114
    private function get_signature_method($request) {
115
 
116
        $signature_method = $request instanceof OAuthRequest
117
            ? $request->get_parameter('oauth_signature_method') : NULL;
118
 
119
        if (!$signature_method) {
120
            // According to chapter 7 ("Accessing Protected Ressources") the signature-method
121
            // parameter is required, and we can't just fallback to PLAINTEXT
122
            throw new OAuthException('No signature method parameter. This parameter is required');
123
        }
124
 
125
        if (!in_array($signature_method,
126
                      array_keys($this->signature_methods))) {
127
            throw new OAuthException(
128
              "Signature method '$signature_method' not supported " .
129
              'try one of the following: ' .
130
              implode(', ', array_keys($this->signature_methods))
131
            );
132
        }
133
 
134
        return $this->signature_methods[$signature_method];
135
 
136
    }
137
 
138
    /**
139
     * try to find the consumer for the provided request's consumer key
140
     */
141
    private function get_consumer($request) {
142
 
143
        $consumer_key = $request instanceof OAuthRequest
144
            ? $request->get_parameter('oauth_consumer_key') : NULL;
145
 
146
        if (!$consumer_key) {
147
            throw new OAuthException('Invalid consumer key');
148
        }
149
 
150
        $consumer = $this->data_store->lookup_consumer($consumer_key);
151
        if (!$consumer) {
152
            throw new OAuthException('Invalid consumer');
153
        }
154
 
155
        return $consumer;
156
 
157
    }
158
 
159
    /**
160
     * try to find the token for the provided request's token key
161
     */
162
    private function get_token($request, $consumer, $token_type="access") {
163
 
164
        $token_field = $request instanceof OAuthRequest
165
             ? $request->get_parameter('oauth_token') : NULL;
166
 
167
        $token = $this->data_store->lookup_token($consumer, $token_type, $token_field);
168
        if (!$token) {
169
            throw new OAuthException("Invalid $token_type token: $token_field");
170
        }
171
 
172
        return $token;
173
 
174
    }
175
 
176
    /**
177
     * all-in-one function to check the signature on a request
178
     * should guess the signature method appropriately
179
     */
180
    private function check_signature($request, $consumer, $token) {
181
 
182
        // this should probably be in a different method
183
        $timestamp = $request instanceof OAuthRequest
184
            ? $request->get_parameter('oauth_timestamp')
185
            : NULL;
186
        $nonce = $request instanceof OAuthRequest
187
            ? $request->get_parameter('oauth_nonce')
188
            : NULL;
189
 
190
        $this->check_timestamp($timestamp);
191
        $this->check_nonce($consumer, $token, $nonce, $timestamp);
192
 
193
        $signature_method = $this->get_signature_method($request);
194
 
195
        $signature = $request->get_parameter('oauth_signature');
196
        $valid_sig = $signature_method->check_signature($request, $consumer, $token, $signature);
197
 
198
        if (!$valid_sig) {
199
            throw new OAuthException('Invalid signature');
200
        }
201
    }
202
 
203
    /**
204
     * check that the timestamp is new enough
205
     */
206
    private function check_timestamp($timestamp) {
207
        if(!$timestamp)
208
            throw new OAuthException('Missing timestamp parameter. The parameter is required');
209
 
210
        // verify that timestamp is recentish
211
        $now = time();
212
        if (abs($now - $timestamp) > $this->timestamp_threshold) {
213
            throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
214
        }
215
 
216
    }
217
 
218
    /**
219
     * check that the nonce is not repeated
220
     */
221
    private function check_nonce($consumer, $token, $nonce, $timestamp) {
222
 
223
        if(!$nonce)
224
          throw new OAuthException('Missing nonce parameter. The parameter is required');
225
 
226
        // verify that the nonce is uniqueish
227
        $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
228
        if ($found) {
229
            throw new OAuthException("Nonce already used: $nonce");
230
        }
231
 
232
    }
233
 
234
}