Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Adding basiclti plugin

  • Loading branch information...
commit b7e436b0373ea6fb377c4d4b7003d38586fb1847 1 parent 735de1c
scriby authored August 25, 2011

Showing 31 changed files with 5,874 additions and 0 deletions. Show diff stats Hide diff stats

  1. 0  log.php b/mod/basiclti/db/log.php
  2. 839  mod/basiclti/OAuth.php
  3. 0  mod/basiclti/TODO.txt
  4. 105  mod/basiclti/TrivialStore.php
  5. 91  mod/basiclti/backup/moodle2/backup_basiclti_activity_task.class.php
  6. 87  mod/basiclti/backup/moodle2/backup_basiclti_stepslib.php
  7. 131  mod/basiclti/backup/moodle2/restore_basiclti_activity_task.class.php
  8. 101  mod/basiclti/backup/moodle2/restore_basiclti_stepslib.php
  9. 56  mod/basiclti/basiclti.js
  10. 71  mod/basiclti/db/access.php
  11. 81  mod/basiclti/db/install.xml
  12. 241  mod/basiclti/db/upgrade.php
  13. 227  mod/basiclti/edit_form.php
  14. 121  mod/basiclti/index.php
  15. 162  mod/basiclti/lang/en/basiclti.php
  16. 1  mod/basiclti/lang/en/help/basiclti/index.html
  17. 1  mod/basiclti/lang/en/help/basiclti/mods.html
  18. 85  mod/basiclti/launch.php
  19. 1,010  mod/basiclti/lib.php
  20. 85  mod/basiclti/localadminlib.php
  21. 757  mod/basiclti/locallib.php
  22. 481  mod/basiclti/mod_form.php
  23. BIN  mod/basiclti/pix/icon.gif
  24. 391  mod/basiclti/service.php
  25. 100  mod/basiclti/settings.php
  26. 89  mod/basiclti/simpletest/testlocallib.php
  27. 29  mod/basiclti/styles.css
  28. 92  mod/basiclti/submissions.php
  29. 258  mod/basiclti/typessettings.php
  30. 50  mod/basiclti/version.php
  31. 132  mod/basiclti/view.php
0  log.php b/mod/basiclti/db/log.php
No changes.
839  mod/basiclti/OAuth.php
... ...
@@ -0,0 +1,839 @@
  1
+<?php
  2
+// This file is part of BasicLTI4Moodle
  3
+//
  4
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
  5
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
  6
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
  7
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
  8
+// are already supporting or going to support BasicLTI. This project Implements the consumer
  9
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
  10
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
  11
+// at the GESSI research group at UPC.
  12
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
  13
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
  14
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
  15
+//
  16
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
  17
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
  18
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
  19
+//
  20
+// OAuth.php is distributed under the MIT License
  21
+//
  22
+// The MIT License
  23
+//
  24
+// Copyright (c) 2007 Andy Smith
  25
+//
  26
+// Permission is hereby granted, free of charge, to any person obtaining a copy
  27
+// of this software and associated documentation files (the "Software"), to deal
  28
+// in the Software without restriction, including without limitation the rights
  29
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  30
+// copies of the Software, and to permit persons to whom the Software is
  31
+// furnished to do so, subject to the following conditions:
  32
+//
  33
+// The above copyright notice and this permission notice shall be included in
  34
+// all copies or substantial portions of the Software.
  35
+//
  36
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  37
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  38
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  39
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  40
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  41
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  42
+// THE SOFTWARE.
  43
+//
  44
+// Moodle is free software: you can redistribute it and/or modify
  45
+// it under the terms of the GNU General Public License as published by
  46
+// the Free Software Foundation, either version 3 of the License, or
  47
+// (at your option) any later version.
  48
+//
  49
+// Moodle is distributed in the hope that it will be useful,
  50
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  51
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  52
+// GNU General Public License for more details.
  53
+//
  54
+// You should have received a copy of the GNU General Public License
  55
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  56
+
  57
+defined('MOODLE_INTERNAL') || die;
  58
+
  59
+$oauth_last_computed_signature = false;
  60
+
  61
+/* Generic exception class
  62
+ */
  63
+class OAuthException extends Exception {
  64
+    // pass
  65
+}
  66
+
  67
+class OAuthConsumer {
  68
+    public $key;
  69
+    public $secret;
  70
+
  71
+    function __construct($key, $secret, $callback_url = null) {
  72
+        $this->key = $key;
  73
+        $this->secret = $secret;
  74
+        $this->callback_url = $callback_url;
  75
+    }
  76
+
  77
+    function __toString() {
  78
+        return "OAuthConsumer[key=$this->key,secret=$this->secret]";
  79
+    }
  80
+}
  81
+
  82
+class OAuthToken {
  83
+    // access tokens and request tokens
  84
+    public $key;
  85
+    public $secret;
  86
+
  87
+    /**
  88
+     * key = the token
  89
+     * secret = the token secret
  90
+     */
  91
+    function __construct($key, $secret) {
  92
+        $this->key = $key;
  93
+        $this->secret = $secret;
  94
+    }
  95
+
  96
+    /**
  97
+     * generates the basic string serialization of a token that a server
  98
+     * would respond to request_token and access_token calls with
  99
+     */
  100
+    function to_string() {
  101
+        return "oauth_token=" .
  102
+        OAuthUtil::urlencode_rfc3986($this->key) .
  103
+        "&oauth_token_secret=" .
  104
+        OAuthUtil::urlencode_rfc3986($this->secret);
  105
+    }
  106
+
  107
+    function __toString() {
  108
+        return $this->to_string();
  109
+    }
  110
+}
  111
+
  112
+class OAuthSignatureMethod {
  113
+    public function check_signature(&$request, $consumer, $token, $signature) {
  114
+        $built = $this->build_signature($request, $consumer, $token);
  115
+        return $built == $signature;
  116
+    }
  117
+}
  118
+
  119
+class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {
  120
+    function get_name() {
  121
+        return "HMAC-SHA1";
  122
+    }
  123
+
  124
+    public function build_signature($request, $consumer, $token) {
  125
+        global $oauth_last_computed_signature;
  126
+        $oauth_last_computed_signature = false;
  127
+
  128
+        $base_string = $request->get_signature_base_string();
  129
+        $request->base_string = $base_string;
  130
+
  131
+        $key_parts = array(
  132
+            $consumer->secret,
  133
+             ($token) ? $token->secret : ""
  134
+        );
  135
+
  136
+        $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
  137
+        $key = implode('&', $key_parts);
  138
+
  139
+        $computed_signature = base64_encode(hash_hmac('sha1', $base_string, $key, true));
  140
+        $oauth_last_computed_signature = $computed_signature;
  141
+        return $computed_signature;
  142
+    }
  143
+
  144
+}
  145
+
  146
+class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {
  147
+    public function get_name() {
  148
+        return "PLAINTEXT";
  149
+    }
  150
+
  151
+    public function build_signature($request, $consumer, $token) {
  152
+        $sig = array(
  153
+            OAuthUtil::urlencode_rfc3986($consumer->secret)
  154
+        );
  155
+
  156
+        if ($token) {
  157
+            array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret));
  158
+        } else {
  159
+            array_push($sig, '');
  160
+        }
  161
+
  162
+        $raw = implode("&", $sig);
  163
+        // for debug purposes
  164
+        $request->base_string = $raw;
  165
+
  166
+        return OAuthUtil::urlencode_rfc3986($raw);
  167
+    }
  168
+}
  169
+
  170
+class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {
  171
+    public function get_name() {
  172
+        return "RSA-SHA1";
  173
+    }
  174
+
  175
+    protected function fetch_public_cert(&$request) {
  176
+        // not implemented yet, ideas are:
  177
+        // (1) do a lookup in a table of trusted certs keyed off of consumer
  178
+        // (2) fetch via http using a url provided by the requester
  179
+        // (3) some sort of specific discovery code based on request
  180
+        //
  181
+        // either way should return a string representation of the certificate
  182
+        throw Exception("fetch_public_cert not implemented");
  183
+    }
  184
+
  185
+    protected function fetch_private_cert(&$request) {
  186
+        // not implemented yet, ideas are:
  187
+        // (1) do a lookup in a table of trusted certs keyed off of consumer
  188
+        //
  189
+        // either way should return a string representation of the certificate
  190
+        throw Exception("fetch_private_cert not implemented");
  191
+    }
  192
+
  193
+    public function build_signature(&$request, $consumer, $token) {
  194
+        $base_string = $request->get_signature_base_string();
  195
+        $request->base_string = $base_string;
  196
+
  197
+        // Fetch the private key cert based on the request
  198
+        $cert = $this->fetch_private_cert($request);
  199
+
  200
+        // Pull the private key ID from the certificate
  201
+        $privatekeyid = openssl_get_privatekey($cert);
  202
+
  203
+        // Sign using the key
  204
+        $ok = openssl_sign($base_string, $signature, $privatekeyid);
  205
+
  206
+        // Release the key resource
  207
+        openssl_free_key($privatekeyid);
  208
+
  209
+        return base64_encode($signature);
  210
+    }
  211
+
  212
+    public function check_signature(&$request, $consumer, $token, $signature) {
  213
+        $decoded_sig = base64_decode($signature);
  214
+
  215
+        $base_string = $request->get_signature_base_string();
  216
+
  217
+        // Fetch the public key cert based on the request
  218
+        $cert = $this->fetch_public_cert($request);
  219
+
  220
+        // Pull the public key ID from the certificate
  221
+        $publickeyid = openssl_get_publickey($cert);
  222
+
  223
+        // Check the computed signature against the one passed in the query
  224
+        $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
  225
+
  226
+        // Release the key resource
  227
+        openssl_free_key($publickeyid);
  228
+
  229
+        return $ok == 1;
  230
+    }
  231
+}
  232
+
  233
+class OAuthRequest {
  234
+    private $parameters;
  235
+    private $http_method;
  236
+    private $http_url;
  237
+    // for debug purposes
  238
+    public $base_string;
  239
+    public static $version = '1.0';
  240
+    public static $POST_INPUT = 'php://input';
  241
+
  242
+    function __construct($http_method, $http_url, $parameters = null) {
  243
+        @$parameters or $parameters = array();
  244
+        $this->parameters = $parameters;
  245
+        $this->http_method = $http_method;
  246
+        $this->http_url = $http_url;
  247
+    }
  248
+
  249
+    /**
  250
+     * attempt to build up a request from what was passed to the server
  251
+     */
  252
+    public static function from_request($http_method = null, $http_url = null, $parameters = null) {
  253
+        $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
  254
+        $port = "";
  255
+        if ($_SERVER['SERVER_PORT'] != "80" && $_SERVER['SERVER_PORT'] != "443" && strpos(':', $_SERVER['HTTP_HOST']) < 0) {
  256
+            $port = ':' . $_SERVER['SERVER_PORT'];
  257
+        }
  258
+        @$http_url or $http_url = $scheme .
  259
+        '://' . $_SERVER['HTTP_HOST'] .
  260
+        $port .
  261
+        $_SERVER['REQUEST_URI'];
  262
+        @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
  263
+
  264
+        // We weren't handed any parameters, so let's find the ones relevant to
  265
+        // this request.
  266
+        // If you run XML-RPC or similar you should use this to provide your own
  267
+        // parsed parameter-list
  268
+        if (!$parameters) {
  269
+            // Find request headers
  270
+            $request_headers = OAuthUtil::get_headers();
  271
+
  272
+            // Parse the query-string to find GET parameters
  273
+            $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
  274
+
  275
+            $ourpost = $_POST;
  276
+            // Deal with magic_quotes
  277
+            // http://www.php.net/manual/en/security.magicquotes.disabling.php
  278
+            if (get_magic_quotes_gpc()) {
  279
+                $outpost = array();
  280
+                foreach ($_POST as $k => $v) {
  281
+                    $v = stripslashes($v);
  282
+                    $ourpost[$k] = $v;
  283
+                }
  284
+            }
  285
+            // Add POST Parameters if they exist
  286
+            $parameters = array_merge($parameters, $ourpost);
  287
+
  288
+            // We have a Authorization-header with OAuth data. Parse the header
  289
+            // and add those overriding any duplicates from GET or POST
  290
+            if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
  291
+                $header_parameters = OAuthUtil::split_header($request_headers['Authorization']);
  292
+                $parameters = array_merge($parameters, $header_parameters);
  293
+            }
  294
+
  295
+        }
  296
+
  297
+        return new OAuthRequest($http_method, $http_url, $parameters);
  298
+    }
  299
+
  300
+    /**
  301
+     * pretty much a helper function to set up the request
  302
+     */
  303
+    public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = null) {
  304
+        @$parameters or $parameters = array();
  305
+        $defaults = array(
  306
+            "oauth_version" => self::$version,
  307
+            "oauth_nonce" => self::generate_nonce(),
  308
+            "oauth_timestamp" => self::generate_timestamp(),
  309
+            "oauth_consumer_key" => $consumer->key
  310
+        );
  311
+        if ($token) {
  312
+            $defaults['oauth_token'] = $token->key;
  313
+        }
  314
+
  315
+        $parameters = array_merge($defaults, $parameters);
  316
+
  317
+        // Parse the query-string to find and add GET parameters
  318
+        $parts = parse_url($http_url);
  319
+        if (isset($parts['query'])) {
  320
+            $qparms = OAuthUtil::parse_parameters($parts['query']);
  321
+            $parameters = array_merge($qparms, $parameters);
  322
+        }
  323
+
  324
+        return new OAuthRequest($http_method, $http_url, $parameters);
  325
+    }
  326
+
  327
+    public function set_parameter($name, $value, $allow_duplicates = true) {
  328
+        if ($allow_duplicates && isset($this->parameters[$name])) {
  329
+            // We have already added parameter(s) with this name, so add to the list
  330
+            if (is_scalar($this->parameters[$name])) {
  331
+                // This is the first duplicate, so transform scalar (string)
  332
+                // into an array so we can add the duplicates
  333
+                $this->parameters[$name] = array($this->parameters[$name]);
  334
+            }
  335
+
  336
+            $this->parameters[$name][] = $value;
  337
+        } else {
  338
+            $this->parameters[$name] = $value;
  339
+        }
  340
+    }
  341
+
  342
+    public function get_parameter($name) {
  343
+        return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
  344
+    }
  345
+
  346
+    public function get_parameters() {
  347
+        return $this->parameters;
  348
+    }
  349
+
  350
+    public function unset_parameter($name) {
  351
+        unset($this->parameters[$name]);
  352
+    }
  353
+
  354
+    /**
  355
+     * The request parameters, sorted and concatenated into a normalized string.
  356
+     * @return string
  357
+     */
  358
+    public function get_signable_parameters() {
  359
+        // Grab all parameters
  360
+        $params = $this->parameters;
  361
+
  362
+        // Remove oauth_signature if present
  363
+        // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
  364
+        if (isset($params['oauth_signature'])) {
  365
+            unset($params['oauth_signature']);
  366
+        }
  367
+
  368
+        return OAuthUtil::build_http_query($params);
  369
+    }
  370
+
  371
+    /**
  372
+     * Returns the base string of this request
  373
+     *
  374
+     * The base string defined as the method, the url
  375
+     * and the parameters (normalized), each urlencoded
  376
+     * and the concated with &.
  377
+     */
  378
+    public function get_signature_base_string() {
  379
+        $parts = array(
  380
+            $this->get_normalized_http_method(),
  381
+            $this->get_normalized_http_url(),
  382
+            $this->get_signable_parameters()
  383
+        );
  384
+
  385
+        $parts = OAuthUtil::urlencode_rfc3986($parts);
  386
+
  387
+        return implode('&', $parts);
  388
+    }
  389
+
  390
+    /**
  391
+     * just uppercases the http method
  392
+     */
  393
+    public function get_normalized_http_method() {
  394
+        return strtoupper($this->http_method);
  395
+    }
  396
+
  397
+    /**
  398
+     * parses the url and rebuilds it to be
  399
+     * scheme://host/path
  400
+     */
  401
+    public function get_normalized_http_url() {
  402
+        $parts = parse_url($this->http_url);
  403
+
  404
+        $port = @$parts['port'];
  405
+        $scheme = $parts['scheme'];
  406
+        $host = $parts['host'];
  407
+        $path = @$parts['path'];
  408
+
  409
+        $port or $port = ($scheme == 'https') ? '443' : '80';
  410
+
  411
+        if (($scheme == 'https' && $port != '443') || ($scheme == 'http' && $port != '80')) {
  412
+            $host = "$host:$port";
  413
+        }
  414
+        return "$scheme://$host$path";
  415
+    }
  416
+
  417
+    /**
  418
+     * builds a url usable for a GET request
  419
+     */
  420
+    public function to_url() {
  421
+        $post_data = $this->to_postdata();
  422
+        $out = $this->get_normalized_http_url();
  423
+        if ($post_data) {
  424
+            $out .= '?'.$post_data;
  425
+        }
  426
+        return $out;
  427
+    }
  428
+
  429
+    /**
  430
+     * builds the data one would send in a POST request
  431
+     */
  432
+    public function to_postdata() {
  433
+        return OAuthUtil::build_http_query($this->parameters);
  434
+    }
  435
+
  436
+    /**
  437
+     * builds the Authorization: header
  438
+     */
  439
+    public function to_header() {
  440
+        $out = 'Authorization: OAuth realm=""';
  441
+        $total = array();
  442
+        foreach ($this->parameters as $k => $v) {
  443
+            if (substr($k, 0, 5) != "oauth") {
  444
+                continue;
  445
+            }
  446
+            if (is_array($v)) {
  447
+                throw new OAuthException('Arrays not supported in headers');
  448
+            }
  449
+            $out .= ',' .
  450
+            OAuthUtil::urlencode_rfc3986($k) .
  451
+            '="' .
  452
+            OAuthUtil::urlencode_rfc3986($v) .
  453
+            '"';
  454
+        }
  455
+        return $out;
  456
+    }
  457
+
  458
+    public function __toString() {
  459
+        return $this->to_url();
  460
+    }
  461
+
  462
+    public function sign_request($signature_method, $consumer, $token) {
  463
+        $this->set_parameter("oauth_signature_method", $signature_method->get_name(), false);
  464
+        $signature = $this->build_signature($signature_method, $consumer, $token);
  465
+        $this->set_parameter("oauth_signature", $signature, false);
  466
+    }
  467
+
  468
+    public function build_signature($signature_method, $consumer, $token) {
  469
+        $signature = $signature_method->build_signature($this, $consumer, $token);
  470
+        return $signature;
  471
+    }
  472
+
  473
+    /**
  474
+     * util function: current timestamp
  475
+     */
  476
+    private static function generate_timestamp() {
  477
+        return time();
  478
+    }
  479
+
  480
+    /**
  481
+     * util function: current nonce
  482
+     */
  483
+    private static function generate_nonce() {
  484
+        $mt = microtime();
  485
+        $rand = mt_rand();
  486
+
  487
+        return md5($mt.$rand); // md5s look nicer than numbers
  488
+    }
  489
+}
  490
+
  491
+class OAuthServer {
  492
+    protected $timestamp_threshold = 300; // in seconds, five minutes
  493
+    protected $version = 1.0; // hi blaine
  494
+    protected $signature_methods = array();
  495
+    protected $data_store;
  496
+
  497
+    function __construct($data_store) {
  498
+        $this->data_store = $data_store;
  499
+    }
  500
+
  501
+    public function add_signature_method($signature_method) {
  502
+        $this->signature_methods[$signature_method->get_name()] = $signature_method;
  503
+    }
  504
+
  505
+    // high level functions
  506
+
  507
+    /**
  508
+     * process a request_token request
  509
+     * returns the request token on success
  510
+     */
  511
+    public function fetch_request_token(&$request) {
  512
+        $this->get_version($request);
  513
+
  514
+        $consumer = $this->get_consumer($request);
  515
+
  516
+        // no token required for the initial token request
  517
+        $token = null;
  518
+
  519
+        $this->check_signature($request, $consumer, $token);
  520
+
  521
+        $new_token = $this->data_store->new_request_token($consumer);
  522
+
  523
+        return $new_token;
  524
+    }
  525
+
  526
+    /**
  527
+     * process an access_token request
  528
+     * returns the access token on success
  529
+     */
  530
+    public function fetch_access_token(&$request) {
  531
+        $this->get_version($request);
  532
+
  533
+        $consumer = $this->get_consumer($request);
  534
+
  535
+        // requires authorized request token
  536
+        $token = $this->get_token($request, $consumer, "request");
  537
+
  538
+        $this->check_signature($request, $consumer, $token);
  539
+
  540
+        $new_token = $this->data_store->new_access_token($token, $consumer);
  541
+
  542
+        return $new_token;
  543
+    }
  544
+
  545
+    /**
  546
+     * verify an api call, checks all the parameters
  547
+     */
  548
+    public function verify_request(&$request) {
  549
+        global $oauth_last_computed_signature;
  550
+        $oauth_last_computed_signature = false;
  551
+        $this->get_version($request);
  552
+        $consumer = $this->get_consumer($request);
  553
+        $token = $this->get_token($request, $consumer, "access");
  554
+        $this->check_signature($request, $consumer, $token);
  555
+        return array(
  556
+            $consumer,
  557
+            $token
  558
+        );
  559
+    }
  560
+
  561
+    // Internals from here
  562
+    /**
  563
+     * version 1
  564
+     */
  565
+    private function get_version(&$request) {
  566
+        $version = $request->get_parameter("oauth_version");
  567
+        if (!$version) {
  568
+            $version = 1.0;
  569
+        }
  570
+        if ($version && $version != $this->version) {
  571
+            throw new OAuthException("OAuth version '$version' not supported");
  572
+        }
  573
+        return $version;
  574
+    }
  575
+
  576
+    /**
  577
+     * figure out the signature with some defaults
  578
+     */
  579
+    private function get_signature_method(&$request) {
  580
+        $signature_method = @ $request->get_parameter("oauth_signature_method");
  581
+        if (!$signature_method) {
  582
+            $signature_method = "PLAINTEXT";
  583
+        }
  584
+        if (!in_array($signature_method, array_keys($this->signature_methods))) {
  585
+            throw new OAuthException("Signature method '$signature_method' not supported " .
  586
+            "try one of the following: " .
  587
+            implode(", ", array_keys($this->signature_methods)));
  588
+        }
  589
+        return $this->signature_methods[$signature_method];
  590
+    }
  591
+
  592
+    /**
  593
+     * try to find the consumer for the provided request's consumer key
  594
+     */
  595
+    private function get_consumer(&$request) {
  596
+        $consumer_key = @ $request->get_parameter("oauth_consumer_key");
  597
+        if (!$consumer_key) {
  598
+            throw new OAuthException("Invalid consumer key");
  599
+        }
  600
+
  601
+        $consumer = $this->data_store->lookup_consumer($consumer_key);
  602
+        if (!$consumer) {
  603
+            throw new OAuthException("Invalid consumer");
  604
+        }
  605
+
  606
+        return $consumer;
  607
+    }
  608
+
  609
+    /**
  610
+     * try to find the token for the provided request's token key
  611
+     */
  612
+    private function get_token(&$request, $consumer, $token_type = "access") {
  613
+        $token_field = @ $request->get_parameter('oauth_token');
  614
+        if (!$token_field) {
  615
+            return false;
  616
+        }
  617
+        $token = $this->data_store->lookup_token($consumer, $token_type, $token_field);
  618
+        if (!$token) {
  619
+            throw new OAuthException("Invalid $token_type token: $token_field");
  620
+        }
  621
+        return $token;
  622
+    }
  623
+
  624
+    /**
  625
+     * all-in-one function to check the signature on a request
  626
+     * should guess the signature method appropriately
  627
+     */
  628
+    private function check_signature(&$request, $consumer, $token) {
  629
+        // this should probably be in a different method
  630
+        global $oauth_last_computed_signature;
  631
+        $oauth_last_computed_signature = false;
  632
+
  633
+        $timestamp = @ $request->get_parameter('oauth_timestamp');
  634
+        $nonce = @ $request->get_parameter('oauth_nonce');
  635
+
  636
+        $this->check_timestamp($timestamp);
  637
+        $this->check_nonce($consumer, $token, $nonce, $timestamp);
  638
+
  639
+        $signature_method = $this->get_signature_method($request);
  640
+
  641
+        $signature = $request->get_parameter('oauth_signature');
  642
+        $valid_sig = $signature_method->check_signature($request, $consumer, $token, $signature);
  643
+
  644
+        if (!$valid_sig) {
  645
+            $ex_text = "Invalid signature";
  646
+            if ($oauth_last_computed_signature) {
  647
+                $ex_text = $ex_text . " ours= $oauth_last_computed_signature yours=$signature";
  648
+            }
  649
+            throw new OAuthException($ex_text);
  650
+        }
  651
+    }
  652
+
  653
+    /**
  654
+     * check that the timestamp is new enough
  655
+     */
  656
+    private function check_timestamp($timestamp) {
  657
+        // verify that timestamp is recentish
  658
+        $now = time();
  659
+        if ($now - $timestamp > $this->timestamp_threshold) {
  660
+            throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
  661
+        }
  662
+    }
  663
+
  664
+    /**
  665
+     * check that the nonce is not repeated
  666
+     */
  667
+    private function check_nonce($consumer, $token, $nonce, $timestamp) {
  668
+        // verify that the nonce is uniqueish
  669
+        $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
  670
+        if ($found) {
  671
+            throw new OAuthException("Nonce already used: $nonce");
  672
+        }
  673
+    }
  674
+
  675
+}
  676
+
  677
+class OAuthDataStore {
  678
+    function lookup_consumer($consumer_key) {
  679
+        // implement me
  680
+    }
  681
+
  682
+    function lookup_token($consumer, $token_type, $token) {
  683
+        // implement me
  684
+    }
  685
+
  686
+    function lookup_nonce($consumer, $token, $nonce, $timestamp) {
  687
+        // implement me
  688
+    }
  689
+
  690
+    function new_request_token($consumer) {
  691
+        // return a new token attached to this consumer
  692
+    }
  693
+
  694
+    function new_access_token($token, $consumer) {
  695
+        // return a new access token attached to this consumer
  696
+        // for the user associated with this token if the request token
  697
+        // is authorized
  698
+        // should also invalidate the request token
  699
+    }
  700
+
  701
+}
  702
+
  703
+class OAuthUtil {
  704
+    public static function urlencode_rfc3986($input) {
  705
+        if (is_array($input)) {
  706
+            return array_map(array(
  707
+                'OAuthUtil',
  708
+                'urlencode_rfc3986'
  709
+            ), $input);
  710
+        } else {
  711
+            if (is_scalar($input)) {
  712
+                return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($input)));
  713
+            } else {
  714
+                return '';
  715
+            }
  716
+        }
  717
+    }
  718
+
  719
+    // This decode function isn't taking into consideration the above
  720
+    // modifications to the encoding process. However, this method doesn't
  721
+    // seem to be used anywhere so leaving it as is.
  722
+    public static function urldecode_rfc3986($string) {
  723
+        return urldecode($string);
  724
+    }
  725
+
  726
+    // Utility function for turning the Authorization: header into
  727
+    // parameters, has to do some unescaping
  728
+    // Can filter out any non-oauth parameters if needed (default behaviour)
  729
+    public static function split_header($header, $only_allow_oauth_parameters = true) {
  730
+        $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
  731
+        $offset = 0;
  732
+        $params = array();
  733
+        while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
  734
+            $match = $matches[0];
  735
+            $header_name = $matches[2][0];
  736
+            $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
  737
+            if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {
  738
+                $params[$header_name] = self::urldecode_rfc3986($header_content);
  739
+            }
  740
+            $offset = $match[1] + strlen($match[0]);
  741
+        }
  742
+
  743
+        if (isset($params['realm'])) {
  744
+            unset($params['realm']);
  745
+        }
  746
+
  747
+        return $params;
  748
+    }
  749
+
  750
+    // helper to try to sort out headers for people who aren't running apache
  751
+    public static function get_headers() {
  752
+        if (function_exists('apache_request_headers')) {
  753
+            // we need this to get the actual Authorization: header
  754
+            // because apache tends to tell us it doesn't exist
  755
+            return apache_request_headers();
  756
+        }
  757
+        // otherwise we don't have apache and are just going to have to hope
  758
+        // that $_SERVER actually contains what we need
  759
+        $out = array();
  760
+        foreach ($_SERVER as $key => $value) {
  761
+            if (substr($key, 0, 5) == "HTTP_") {
  762
+                // this is chaos, basically it is just there to capitalize the first
  763
+                // letter of every word that is not an initial HTTP and strip HTTP
  764
+                // code from przemek
  765
+                $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
  766
+                $out[$key] = $value;
  767
+            }
  768
+        }
  769
+        return $out;
  770
+    }
  771
+
  772
+    // This function takes a input like a=b&a=c&d=e and returns the parsed
  773
+    // parameters like this
  774
+    // array('a' => array('b','c'), 'd' => 'e')
  775
+    public static function parse_parameters($input) {
  776
+        if (!isset($input) || !$input) {
  777
+            return array();
  778
+        }
  779
+
  780
+        $pairs = explode('&', $input);
  781
+
  782
+        $parsed_parameters = array();
  783
+        foreach ($pairs as $pair) {
  784
+            $split = explode('=', $pair, 2);
  785
+            $parameter = self::urldecode_rfc3986($split[0]);
  786
+            $value = isset($split[1]) ? self::urldecode_rfc3986($split[1]) : '';
  787
+
  788
+            if (isset($parsed_parameters[$parameter])) {
  789
+                // We have already recieved parameter(s) with this name, so add to the list
  790
+                // of parameters with this name
  791
+
  792
+                if (is_scalar($parsed_parameters[$parameter])) {
  793
+                    // This is the first duplicate, so transform scalar (string) into an array
  794
+                    // so we can add the duplicates
  795
+                    $parsed_parameters[$parameter] = array(
  796
+                        $parsed_parameters[$parameter]
  797
+                    );
  798
+                }
  799
+
  800
+                $parsed_parameters[$parameter][] = $value;
  801
+            } else {
  802
+                $parsed_parameters[$parameter] = $value;
  803
+            }
  804
+        }
  805
+        return $parsed_parameters;
  806
+    }
  807
+
  808
+    public static function build_http_query($params) {
  809
+        if (!$params) {
  810
+            return '';
  811
+        }
  812
+
  813
+        // Urlencode both keys and values
  814
+        $keys = self::urlencode_rfc3986(array_keys($params));
  815
+        $values = self::urlencode_rfc3986(array_values($params));
  816
+        $params = array_combine($keys, $values);
  817
+
  818
+        // Parameters are sorted by name, using lexicographical byte value ordering.
  819
+        // Ref: Spec: 9.1.1 (1)
  820
+        uksort($params, 'strcmp');
  821
+
  822
+        $pairs = array();
  823
+        foreach ($params as $parameter => $value) {
  824
+            if (is_array($value)) {
  825
+                // If two or more parameters share the same name, they are sorted by their value
  826
+                // Ref: Spec: 9.1.1 (1)
  827
+                natsort($value);
  828
+                foreach ($value as $duplicate_value) {
  829
+                    $pairs[] = $parameter . '=' . $duplicate_value;
  830
+                }
  831
+            } else {
  832
+                $pairs[] = $parameter . '=' . $value;
  833
+            }
  834
+        }
  835
+        // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
  836
+        // Each name-value pair is separated by an '&' character (ASCII code 38)
  837
+        return implode('&', $pairs);
  838
+    }
  839
+}
0  mod/basiclti/TODO.txt
No changes.
105  mod/basiclti/TrivialStore.php
... ...
@@ -0,0 +1,105 @@
  1
+<?php
  2
+// This file is part of BasicLTI4Moodle
  3
+//
  4
+// Licensed to the Apache Software Foundation (ASF) under one
  5
+// or more contributor license agreements.  See the NOTICE file
  6
+// distributed with this work for additional information
  7
+// regarding copyright ownership.  The ASF licenses this file
  8
+// to you under the Apache License, Version 2.0 (the
  9
+// "License"); you may not use this file except in compliance
  10
+// with the License.  You may obtain a copy of the License at
  11
+//
  12
+// http://www.apache.org/licenses/LICENSE-2.0
  13
+//
  14
+// Unless required by applicable law or agreed to in writing,
  15
+// software distributed under the License is distributed on an
  16
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17
+// KIND, either express or implied.  See the License for the
  18
+// specific language governing permissions and limitations
  19
+// under the License.
  20
+//
  21
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
  22
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
  23
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
  24
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
  25
+// are already supporting or going to support BasicLTI. This project Implements the consumer
  26
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
  27
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
  28
+// at the GESSI research group at UPC.
  29
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
  30
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
  31
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
  32
+//
  33
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
  34
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
  35
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
  36
+//
  37
+// Moodle is free software: you can redistribute it and/or modify
  38
+// it under the terms of the GNU General Public License as published by
  39
+// the Free Software Foundation, either version 3 of the License, or
  40
+// (at your option) any later version.
  41
+//
  42
+// Moodle is distributed in the hope that it will be useful,
  43
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  44
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  45
+// GNU General Public License for more details.
  46
+//
  47
+// You should have received a copy of the GNU General Public License
  48
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  49
+
  50
+/**
  51
+ * This file contains a Trivial memory-based store - no support for tokens
  52
+ *
  53
+ * @package basiclti
  54
+ * @copyright IMS Global Learning Consortium
  55
+ *
  56
+ * @author Charles Severance csev@umich.edu
  57
+ *
  58
+ * @license http://www.apache.org/licenses/LICENSE-2.0
  59
+ */
  60
+
  61
+defined('MOODLE_INTERNAL') || die;
  62
+
  63
+/**
  64
+ * A Trivial memory-based store - no support for tokens
  65
+ */
  66
+class TrivialOAuthDataStore extends OAuthDataStore {
  67
+    private $consumers = array();
  68
+
  69
+    function add_consumer($consumer_key, $consumer_secret) {
  70
+        $this->consumers[$consumer_key] = $consumer_secret;
  71
+    }
  72
+
  73
+    function lookup_consumer($consumer_key) {
  74
+        if ( strpos($consumer_key, "http://" ) === 0 ) {
  75
+            $consumer = new OAuthConsumer($consumer_key, "secret", null);
  76
+            return $consumer;
  77
+        }
  78
+        if ( $this->consumers[$consumer_key] ) {
  79
+            $consumer = new OAuthConsumer($consumer_key, $this->consumers[$consumer_key], null);
  80
+            return $consumer;
  81
+        }
  82
+        return null;
  83
+    }
  84
+
  85
+    function lookup_token($consumer, $token_type, $token) {
  86
+        return new OAuthToken($consumer, "");
  87
+    }
  88
+
  89
+    // Return NULL if the nonce has not been used
  90
+    // Return $nonce if the nonce was previously used
  91
+    function lookup_nonce($consumer, $token, $nonce, $timestamp) {
  92
+        // Should add some clever logic to keep nonces from
  93
+        // being reused - for no we are really trusting
  94
+        // that the timestamp will save us
  95
+        return null;
  96
+    }
  97
+
  98
+    function new_request_token($consumer) {
  99
+        return null;
  100
+    }
  101
+
  102
+    function new_access_token($token, $consumer) {
  103
+        return null;
  104
+    }
  105
+}
91  mod/basiclti/backup/moodle2/backup_basiclti_activity_task.class.php
... ...
@@ -0,0 +1,91 @@
  1
+<?php
  2
+// This file is part of BasicLTI4Moodle
  3
+//
  4
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
  5
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
  6
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
  7
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
  8
+// are already supporting or going to support BasicLTI. This project Implements the consumer
  9
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
  10
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
  11
+// at the GESSI research group at UPC.
  12
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
  13
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
  14
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
  15
+//
  16
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
  17
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
  18
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
  19
+//
  20
+// Moodle is free software: you can redistribute it and/or modify
  21
+// it under the terms of the GNU General Public License as published by
  22
+// the Free Software Foundation, either version 3 of the License, or
  23
+// (at your option) any later version.
  24
+//
  25
+// Moodle is distributed in the hope that it will be useful,
  26
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  27
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28
+// GNU General Public License for more details.
  29
+//
  30
+// You should have received a copy of the GNU General Public License
  31
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  32
+
  33
+
  34
+/**
  35
+ * This file contains the basiclti module backup class
  36
+ *
  37
+ * @package basiclti
  38
+ * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  39
+ *  marc.alier@upc.edu
  40
+ * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
  41
+ *
  42
+ * @author Marc Alier
  43
+ * @author Jordi Piguillem
  44
+ * @author Nikolas Galanis
  45
+ *
  46
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  47
+ */
  48
+
  49
+require_once($CFG->dirroot . '/mod/basiclti/backup/moodle2/backup_basiclti_stepslib.php');
  50
+
  51
+/**
  52
+ * basiclti backup task that provides all the settings and steps to perform one
  53
+ * complete backup of the module
  54
+ */
  55
+class backup_basiclti_activity_task extends backup_activity_task {
  56
+
  57
+    /**
  58
+     * Define (add) particular settings this activity can have
  59
+     */
  60
+    protected function define_my_settings() {
  61
+        // No particular settings for this activity
  62
+    }
  63
+
  64
+    /**
  65
+     * Define (add) particular steps this activity can have
  66
+     */
  67
+    protected function define_my_steps() {
  68
+        // Choice only has one structure step
  69
+        $this->add_step(new backup_basiclti_activity_structure_step('basiclti_structure', 'basiclti.xml'));
  70
+    }
  71
+
  72
+    /**
  73
+     * Code the transformations to perform in the activity in
  74
+     * order to get transportable (encoded) links
  75
+     */
  76
+    static public function encode_content_links($content) {
  77
+        global $CFG;
  78
+
  79
+        $base = preg_quote($CFG->wwwroot, "/");
  80
+
  81
+        // Link to the list of basiclti tools
  82
+        $search="/(".$base."\/mod\/basiclti\/index.php\?id\=)([0-9]+)/";
  83
+        $content= preg_replace($search, '$@BASICLTIINDEX*$2@$', $content);
  84
+
  85
+        // Link to basiclti view by moduleid
  86
+        $search="/(".$base."\/mod\/basiclti\/view.php\?id\=)([0-9]+)/";
  87
+        $content= preg_replace($search, '$@BASICLTIVIEWBYID*$2@$', $content);
  88
+
  89
+        return $content;
  90
+    }
  91
+}
87  mod/basiclti/backup/moodle2/backup_basiclti_stepslib.php
... ...
@@ -0,0 +1,87 @@
  1
+<?php
  2
+// This file is part of BasicLTI4Moodle
  3
+//
  4
+// BasicLTI4Moodle is an IMS BasicLTI (Basic Learning Tools for Interoperability)
  5
+// consumer for Moodle 1.9 and Moodle 2.0. BasicLTI is a IMS Standard that allows web
  6
+// based learning tools to be easily integrated in LMS as native ones. The IMS BasicLTI
  7
+// specification is part of the IMS standard Common Cartridge 1.1 Sakai and other main LMS
  8
+// are already supporting or going to support BasicLTI. This project Implements the consumer
  9
+// for Moodle. Moodle is a Free Open source Learning Management System by Martin Dougiamas.
  10
+// BasicLTI4Moodle is a project iniciated and leaded by Ludo(Marc Alier) and Jordi Piguillem
  11
+// at the GESSI research group at UPC.
  12
+// SimpleLTI consumer for Moodle is an implementation of the early specification of LTI
  13
+// by Charles Severance (Dr Chuck) htp://dr-chuck.com , developed by Jordi Piguillem in a
  14
+// Google Summer of Code 2008 project co-mentored by Charles Severance and Marc Alier.
  15
+//
  16
+// BasicLTI4Moodle is copyright 2009 by Marc Alier Forment, Jordi Piguillem and Nikolas Galanis
  17
+// of the Universitat Politecnica de Catalunya http://www.upc.edu
  18
+// Contact info: Marc Alier Forment granludo @ gmail.com or marc.alier @ upc.edu
  19
+//
  20
+// Moodle is free software: you can redistribute it and/or modify
  21
+// it under the terms of the GNU General Public License as published by
  22
+// the Free Software Foundation, either version 3 of the License, or
  23
+// (at your option) any later version.
  24
+//
  25
+// Moodle is distributed in the hope that it will be useful,
  26
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  27
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  28
+// GNU General Public License for more details.
  29
+//
  30
+// You should have received a copy of the GNU General Public License
  31
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  32
+
  33
+/**
  34
+ * This file contains all the backup steps that will be used
  35
+ * by the backup_basiclti_activity_task
  36
+ *
  37
+ * @package basiclti
  38
+ * @copyright 2009 Marc Alier, Jordi Piguillem, Nikolas Galanis
  39
+ *  marc.alier@upc.edu
  40
+ * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
  41
+ *
  42
+ * @author Marc Alier
  43
+ * @author Jordi Piguillem
  44
+ * @author Nikolas Galanis
  45
+ *
  46
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  47
+ */
  48
+
  49
+/**
  50
+ * Define all the backup steps that will be used by the backup_basiclti_activity_task
  51
+ */