Skip to content
Merged

auth #17

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,18 @@ public function __construct() {
*/
public function user_login($username, $password = null) {
global $CFG, $DB;
if ($DB->get_record('user', ['username' => $username, 'mnethostid' => $CFG->mnet_localhost_id])) {
return true;

if (empty($password)) {
return false;
}
return false;

$user = $DB->get_record('user', ['username' => $username, 'mnethostid' => $CFG->mnet_localhost_id]);

if (empty($user) || !empty($user->suspended)) {
return false;
}

return validate_internal_user_password($user, $password);
}

/**
Expand Down
35 changes: 35 additions & 0 deletions db/access.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Capability definitions.
*
* @package auth_moowoodle
* @author DualCube <admin@dualcube.com>
* @copyright DualCube (https://dualcube.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

$capabilities = [
'auth/moowoodle:syncusers' => [
'riskbitmask' => RISK_PERSONAL,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => [],
'clonepermissionsfrom' => 'moodle/site:config',
],
];
108 changes: 82 additions & 26 deletions externallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,40 @@ public static function auth_moowoodle_get_users_parameters(): \external_function
*/
public static function auth_moowoodle_get_users($endid, $limit, $roles) {
global $DB;

if (is_numeric($limit) && is_numeric($endid)) {

$limit = (int) $limit + 1;

// Sanitize role IDs and prepare SQL placeholders.
$roleids = explode(',', $roles);
$roleids = array_map('intval', $roleids);

list($rolesql, $roleparams) = $DB->get_in_or_equal(
$roleids,
SQL_PARAMS_NAMED,
'roleid'
);

$sql = "SELECT u.id, u.email, u.username, u.password, u.firstname, u.lastname
FROM {user} u
JOIN {role_assignments} ra ON u.id = ra.userid
WHERE u.id > :endid AND u.deleted = 0 AND ra.roleid IN ( " . $roles . " )
ORDER BY u.id ASC";
$param = [
'endid' => (int) $endid,
];
if ( $limit <= 0 ) {
FROM {user} u
JOIN {role_assignments} ra ON u.id = ra.userid
WHERE u.id > :endid
AND u.deleted = 0
AND ra.roleid $rolesql
ORDER BY u.id ASC";

$param = array_merge(
[
'endid' => (int) $endid,
],
$roleparams
);

if ($limit <= 0) {
$response = [
'status' => 'success',
'data' => json_encode( $DB->get_records_sql( $sql, $param ) ),
'data' => json_encode($DB->get_records_sql($sql, $param)),
];
} else {
$response = [
Expand All @@ -82,6 +102,7 @@ public static function auth_moowoodle_get_users($endid, $limit, $roles) {
'data' => json_encode('Bad Request'),
];
}

return ($response);
}
/**
Expand Down Expand Up @@ -118,31 +139,63 @@ public static function auth_moowoodle_user_sync_parameters(): \external_function
*/
public static function auth_moowoodle_user_sync( $userdata, $setting ) {
global $DB, $CFG;

// Validate input parameters.
$params = self::validate_parameters(
self::auth_moowoodle_user_sync_parameters(),
[
'userdata' => $userdata,
'setting' => $setting,
]
);

$userdata = $params['userdata'];
$setting = $params['setting'];

// Validate context.
$context = \context_system::instance();
self::validate_context( $context );

// Require capability.
require_capability( 'auth/moowoodle:syncusers', $context );

// Decode JSON.
$wpuserdata = json_decode( $userdata, true );
$syncsettings = json_decode( $setting, true );

if ( json_last_error() !== JSON_ERROR_NONE ) {
throw new invalid_parameter_exception( 'Invalid JSON payload.' );
}

if ( is_array( $wpuserdata ) && is_array( $syncsettings ) ) {
require_once($CFG->dirroot . '/user/lib.php');
$moodleuserdata = $DB->get_record( 'user', [ 'email' => $wpuserdata[ 'email' ] ] );
$response[ 'created' ] = false;
require_once( $CFG->dirroot . '/user/lib.php' );

$moodleuserdata = $DB->get_record( 'user', [ 'email' => $wpuserdata['email'], 'deleted' => 0 ] );
$response['created'] = false;

if ( ! $moodleuserdata->id ) {
$moodleuserdata = new stdClass();
}
$moodleuserdata->email = $wpuserdata[ 'email' ];

$moodleuserdata->email = clean_param($wpuserdata['email'], PARAM_EMAIL);

if ( in_array( 'username', $syncsettings ) || ! $moodleuserdata->id ) {
$moodleuserdata->username = $wpuserdata[ 'username' ];
$moodleuserdata->username = clean_param($wpuserdata['username'], PARAM_USERNAME);
}
$updatepassword = false;
if ( in_array( 'password', $syncsettings ) && $wpuserdata[ 'password' ] != null || ! $moodleuserdata->id ) {
if ( strpos( $wpuserdata[ 'password' ], '$6$rounds=' ) === 0 ) {
$moodleuserdata->password = $wpuserdata[ 'password' ];

if ( ( in_array( 'password', $syncsettings ) && $wpuserdata['password'] != null ) || ! $moodleuserdata->id ) {

if ( strpos( $wpuserdata['password'], '$6$rounds=' ) === 0 ) {
$moodleuserdata->password = $wpuserdata['password'];
}
}
if ( in_array( 'firstname', $syncsettings ) && $wpuserdata[ 'firstname' ] != null || ! $moodleuserdata->id ) {
$moodleuserdata->firstname = $wpuserdata[ 'firstname' ];

if ( ( in_array( 'firstname', $syncsettings ) && $wpuserdata['firstname'] != null ) || ! $moodleuserdata->id ) {
$moodleuserdata->firstname = clean_param($wpuserdata['firstname'] ?? '', PARAM_NOTAGS);
}
if ( in_array( 'lastname', $syncsettings ) && $wpuserdata[ 'lastname' ] != null || ! $moodleuserdata->id ) {
$moodleuserdata->lastname = $wpuserdata[ 'lastname' ];

if ( ( in_array( 'lastname', $syncsettings ) && $wpuserdata['lastname'] != null ) || ! $moodleuserdata->id ) {
$moodleuserdata->lastname = clean_param($wpuserdata['lastname'] ?? '', PARAM_NOTAGS);
}

$moodleuserdata->confirmed = true;
Expand All @@ -153,10 +206,11 @@ public static function auth_moowoodle_user_sync( $userdata, $setting ) {
$userid = $moodleuserdata->id;
} else {
$userid = user_create_user( $moodleuserdata, false, false );
$response[ 'created' ] = true;
$response['created'] = true;
}

$response[ 'id' ] = $userid;
$response['id'] = $userid;

$response = [
'status' => 'success',
'data' => json_encode( $response ),
Expand All @@ -167,8 +221,10 @@ public static function auth_moowoodle_user_sync( $userdata, $setting ) {
'data' => json_encode( 'Bad Request' ),
];
}
return ( $response );

return $response;
}

/**
* Returns description of method result value
* @return external_description
Expand Down
73 changes: 43 additions & 30 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,33 +24,41 @@

require_once ( '../../config.php' );
require_once ( $CFG->libdir . '/filelib.php' );
require_once(__DIR__ . '/lib.php');

$SESSION->wantsurl = $CFG->wwwroot . '/';

$passkey = optional_param( 'passkey', '', PARAM_RAW );

if ( $passkey ) {
$requestdata = base64_decode( $passkey );
$requestdata = json_decode( $requestdata, true );
$sso_key = get_config('auth_moowoodle', 'encryptkey');

$requestdata = moowoodle_decrypt_data($passkey, $sso_key);

if (false === $requestdata) {
throw new moodle_exception('Invalid SSO token.');
}

// Get timestamp.
$timestamp = $requestdata[ 'timestamp' ];
$timestamp = $requestdata['timestamp'];

// Calculate time difference.
$timedif = time() - $timestamp;

$userexist = $DB->record_exists( 'user', [ 'id' => $requestdata[ 'user_id' ] ] );

if ( $timedif < get_config( 'auth_moowoodle', 'timelimit' ) * 60 && $userexist ) {
$userexist = $DB->record_exists('user', ['id' => $requestdata['user_id']]);

// Get the user data
$user = get_complete_user_data( 'id', $requestdata[ 'user_id' ] );

// Get wordpress requset url
$requesturl = get_config( 'auth_moowoodle', 'wpsiteurl' ) . '/?rest_route=/moowoodle/v1/sso';
if ( $timedif >= 0 && $timedif < get_config('auth_moowoodle', 'timelimit') * 60 && $userexist ) {

$user = get_complete_user_data( 'id', $requestdata['user_id'] );

// Get wordpress request url.
$requesturl = get_config('auth_moowoodle', 'wpsiteurl') . '/?rest_route=/moowoodle/v1/sso';

$curl = new curl();

// Prepare request data
$request_token = bin2hex(random_bytes(32));

// Prepare request data.
$reqdata = [
'action' => 'login_verify',
'redirect_to' => $requestdata['redirect_url'],
Expand All @@ -60,48 +68,53 @@
'timestamp' => $requestdata['timestamp'],
'course_id' => $requestdata['course_id'],
'user_id' => $requestdata['wp_user_id'],
'one_time_code' => $passkey,
'nonce' => $requestdata['nonce'],
'request_token' => $request_token,
];

$encrypted_request = moowoodle_encrypt_data($reqdata, $sso_key);

if (false === $encrypted_request) {
throw new moodle_exception('Unable to encrypt SSO request.');
}

// Send request to wordpress server.
$response = $curl->post(
$requesturl,
$reqdata,
[
'payload' => $encrypted_request,
],
[
'RETURNTRANSFER' => 1,
'TIMEOUT' => 100,
]
);
$response = json_decode( $response, true );

$response = json_decode($response, true);

if ( ! $response ) {
throw new moodle_exception( $curl->error );
throw new moodle_exception($curl->error);
}

if ( $response[ 'status' ] == 'unauthorized' ) {
throw new moodle_exception( 'Unauthorized access, contact with site admin.' );
if ( $response['status'] == 'unauthorized' ) {
throw new moodle_exception('Unauthorized access, contact with site admin.');
}

if ( $response[ 'moowoodle_one_time_code' ] != $passkey ) {
throw new moodle_exception( 'Unauthorized access, one-time-code mismatch.' );
if ( empty($response['request_token']) || ! hash_equals( $request_token, $response['request_token'] ) ) {
throw new moodle_exception( 'Unauthorized access, request-token mismatch.');
}

if ( $response[ 'sskey' ] != md5( get_config( 'auth_moowoodle', 'encryptkey') ) ) {
throw new moodle_exception( 'Unauthorized access, sskey mismatch.' );
}

if ( $response[ 'status' ] == 'success' ) {
if ( $response['status'] == 'success' ) {
$user->loggedin = true;
$user->site = $CFG->wwwroot;
unset_user_preference( 'auth_forcepasswordchange', $user );
unset_user_preference('auth_forcepasswordchange', $user);
complete_user_login($user);
}

if ( $requestdata[ 'redirect_url' ] ) {
$SESSION->wantsurl = $requestdata[ 'redirect_url' ];
if ( !empty($requestdata['redirect_url']) && parse_url($requestdata['redirect_url'], PHP_URL_HOST) === parse_url($CFG->wwwroot, PHP_URL_HOST) ) {
$SESSION->wantsurl = $requestdata['redirect_url'];
}
}
}

redirect( $SESSION->wantsurl );
redirect($SESSION->wantsurl);
Loading