From 1582d54bb0556a6c401c7b7f7c8fe8e0d74531cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Massart?= Date: Sun, 29 Apr 2018 11:47:20 +0800 Subject: [PATCH] MDL-62253 core_auth: Implement privacy API --- auth/classes/privacy/provider.php | 103 ++++++++++++++++++++++++++++++ auth/tests/privacy_test.php | 103 ++++++++++++++++++++++++++++++ lang/en/auth.php | 8 +++ 3 files changed, 214 insertions(+) create mode 100644 auth/classes/privacy/provider.php create mode 100644 auth/tests/privacy_test.php diff --git a/auth/classes/privacy/provider.php b/auth/classes/privacy/provider.php new file mode 100644 index 0000000000000..1c61c57958caf --- /dev/null +++ b/auth/classes/privacy/provider.php @@ -0,0 +1,103 @@ +. + +/** + * Data provider. + * + * @package core_auth + * @copyright 2018 Frédéric Massart + * @author Frédéric Massart + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_auth\privacy; +defined('MOODLE_INTERNAL') || die(); + +use context; +use core_privacy\local\metadata\collection; +use core_privacy\local\request\transform; +use core_privacy\local\request\writer; + +/** + * Data provider class. + * + * @package core_auth + * @copyright 2018 Frédéric Massart + * @author Frédéric Massart + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements + \core_privacy\local\metadata\provider, + \core_privacy\local\request\user_preference_provider { + + /** + * Returns metadata. + * + * @param collection $collection The initialised collection to add items to. + * @return collection A listing of user data stored through this system. + */ + public static function get_metadata(collection $collection) : collection { + + $collection->add_user_preference('auth_forcepasswordchange', 'privacy:metadata:userpref:forcepasswordchange'); + $collection->add_user_preference('create_password', 'privacy:metadata:userpref:createpassword'); + $collection->add_user_preference('login_failed_count', 'privacy:metadata:userpref:loginfailedcount'); + $collection->add_user_preference('login_failed_count_since_success', + 'privacy:metadata:userpref:loginfailedcountsincesuccess'); + $collection->add_user_preference('login_failed_last', 'privacy:metadata:userpref:loginfailedlast'); + $collection->add_user_preference('login_lockout', 'privacy:metadata:userpref:loginlockout'); + $collection->add_user_preference('login_lockout_ignored', 'privacy:metadata:userpref:loginlockoutignored'); + $collection->add_user_preference('login_lockout_secret', 'privacy:metadata:userpref:loginlockoutsecret'); + + return $collection; + } + + /** + * Export all user preferences for the plugin. + * + * @param int $userid The userid of the user whose data is to be exported. + */ + public static function export_user_preferences(int $userid) { + + $yesno = function($v) { + return transform::yesno($v); + }; + $datetime = function($v) { + return $v ? transform::datetime($v) : null; + }; + + $prefs = [ + ['auth_forcepasswordchange', 'forcepasswordchange', $yesno], + ['create_password', 'createpassword', $yesno], + ['login_failed_count', 'loginfailedcount', null], + ['login_failed_count_since_success', 'loginfailedcountsincesuccess', null], + ['login_failed_last', 'loginfailedlast', $datetime], + ['login_lockout', 'loginlockout', $datetime], + ['login_lockout_ignored', 'loginlockoutignored', $yesno], + ['login_lockout_secret', 'loginlockoutsecret', null], + ]; + + foreach ($prefs as $prefdata) { + list($prefname, $langkey, $transformer) = $prefdata; + $value = get_user_preferences($prefname, null, $userid); + if ($value === null) { + continue; + } + writer::export_user_preference('core_auth', $prefname, $transformer ? $transformer($value) : $value, + get_string("privacy:metadata:userpref:{$langkey}", 'core_auth')); + } + } + +} diff --git a/auth/tests/privacy_test.php b/auth/tests/privacy_test.php new file mode 100644 index 0000000000000..16701f26f8036 --- /dev/null +++ b/auth/tests/privacy_test.php @@ -0,0 +1,103 @@ +. + +/** + * Data provider tests. + * + * @package core_auth + * @category test + * @copyright 2018 Frédéric Massart + * @author Frédéric Massart + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +global $CFG; + +use core_privacy\tests\provider_testcase; +use core_privacy\local\request\transform; +use core_privacy\local\request\writer; +use core_auth\privacy\provider; + +/** + * Data provider testcase class. + * + * @package core_auth + * @category test + * @copyright 2018 Frédéric Massart + * @author Frédéric Massart + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_auth_privacy_testcase extends provider_testcase { + + public function setUp() { + $this->resetAfterTest(); + } + + public function test_export_user_preferences() { + $dg = $this->getDataGenerator(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $sysctx = context_system::instance(); + $now = time(); + + // Check nothing is there. + writer::reset(); + provider::export_user_preferences($u1->id); + $prefs = writer::with_context($sysctx)->get_user_preferences('core_auth'); + $this->assertEmpty((array) $prefs); + + // Set some preferences. + set_user_preference('auth_forcepasswordchange', 1, $u1); + set_user_preference('create_password', 1, $u1); + set_user_preference('login_failed_count', 18, $u1); + set_user_preference('login_failed_count_since_success', 7, $u1); + set_user_preference('login_failed_last', $now - DAYSECS, $u1); + set_user_preference('login_lockout', $now - HOURSECS, $u1); + set_user_preference('login_lockout_ignored', 0, $u1); + set_user_preference('login_lockout_secret', 'Hello world!', $u1); + + set_user_preference('auth_forcepasswordchange', 0, $u2); + set_user_preference('create_password', 0, $u2); + set_user_preference('login_lockout_ignored', 1, $u2); + + // Check user 1. + writer::reset(); + provider::export_user_preferences($u1->id); + $prefs = writer::with_context($sysctx)->get_user_preferences('core_auth'); + $this->assertEquals(transform::yesno(true), $prefs->auth_forcepasswordchange->value); + $this->assertEquals(transform::yesno(true), $prefs->create_password->value); + $this->assertEquals(18, $prefs->login_failed_count->value); + $this->assertEquals(7, $prefs->login_failed_count_since_success->value); + $this->assertEquals(transform::datetime($now - DAYSECS), $prefs->login_failed_last->value); + $this->assertEquals(transform::datetime($now - HOURSECS), $prefs->login_lockout->value); + $this->assertEquals(transform::yesno(false), $prefs->login_lockout_ignored->value); + $this->assertEquals('Hello world!', $prefs->login_lockout_secret->value); + + // Check user 2. + writer::reset(); + provider::export_user_preferences($u2->id); + $prefs = writer::with_context($sysctx)->get_user_preferences('core_auth'); + $this->assertEquals(transform::yesno(false), $prefs->auth_forcepasswordchange->value); + $this->assertEquals(transform::yesno(false), $prefs->create_password->value); + $this->assertObjectNotHasAttribute('login_failed_count', $prefs); + $this->assertObjectNotHasAttribute('login_failed_count_since_success', $prefs); + $this->assertObjectNotHasAttribute('login_failed_last', $prefs); + $this->assertObjectNotHasAttribute('login_lockout', $prefs); + $this->assertEquals(transform::yesno(true), $prefs->login_lockout_ignored->value); + $this->assertObjectNotHasAttribute('login_lockout_secret', $prefs); + } +} diff --git a/lang/en/auth.php b/lang/en/auth.php index c5185e29bc3c9..b358466039319 100644 --- a/lang/en/auth.php +++ b/lang/en/auth.php @@ -138,6 +138,14 @@ $string['plaintext'] = 'Plain text'; $string['pluginnotenabled'] = 'Authentication plugin \'{$a}\' is not enabled.'; $string['pluginnotinstalled'] = 'Authentication plugin \'{$a}\' is not installed.'; +$string['privacy:metadata:userpref:createpassword'] = 'Indicates that a password should be generated for the user'; +$string['privacy:metadata:userpref:forcepasswordchange'] = 'Indicates whether the user should change their password upon logging in'; +$string['privacy:metadata:userpref:loginfailedcount'] = 'The number of times the user failed to log in'; +$string['privacy:metadata:userpref:loginfailedcountsincesuccess'] = 'The number of times the user failed to login since their last successful login'; +$string['privacy:metadata:userpref:loginfailedlast'] = 'The date at which the last failed login attempt was recorded'; +$string['privacy:metadata:userpref:loginlockout'] = 'Indicates whether the user\'s account is locked due to failed login attempts, and the date at which the account entered the lockout state'; +$string['privacy:metadata:userpref:loginlockoutignored'] = 'Indicates that a user\'s account should never be subject to lockouts'; +$string['privacy:metadata:userpref:loginlockoutsecret'] = 'When locked, the secret the user must use for unlocking their account'; $string['potentialidps'] = 'Log in using your account on:'; $string['recaptcha'] = 'reCAPTCHA'; $string['recaptcha_help'] = 'The CAPTCHA is for preventing abuse from automated programs. Follow the instructions to verify you are a person. This could be a box to check, characters presented in an image you must enter or a set of images to select from.