diff --git a/.upgrade.yml b/.upgrade.yml index 04527a424..8361de682 100644 --- a/.upgrade.yml +++ b/.upgrade.yml @@ -115,8 +115,49 @@ mappings: VersionedGridFieldDetailForm: SilverStripe\ORM\Versioning\VersionedGridFieldDetailForm VersionedGridFieldItemRequest: SilverStripe\ORM\Versioning\VersionedGridFieldItemRequest Hierarchy: SilverStripe\ORM\Hierarchy\Hierarchy + Authenticator: SilverStripe\Security\Authenticator + BasicAuth: SilverStripe\Security\BasicAuth + ChangePasswordForm: SilverStripe\Security\ChangePasswordForm + CMSMemberLoginForm: SilverStripe\Security\CMSMemberLoginForm + CMSSecurity: SilverStripe\Security\CMSSecurity + Group: SilverStripe\Security\Group + GroupCsvBulkLoader: SilverStripe\Security\GroupCsvBulkLoader + LoginAttempt: SilverStripe\Security\LoginAttempt + LoginForm: SilverStripe\Security\LoginForm + Member: SilverStripe\Security\Member + Member_GroupSet: SilverStripe\Security\Member_GroupSet + Member_Validator: SilverStripe\Security\Member_Validator + MemberAuthenticator: SilverStripe\Security\MemberAuthenticator + MemberCsvBulkLoader: SilverStripe\Security\MemberCsvBulkLoader + MemberLoginForm: SilverStripe\Security\MemberLoginForm + MemberPassword: SilverStripe\Security\MemberPassword + PasswordEncryptor: SilverStripe\Security\PasswordEncryptor + PasswordEncryptor_Blowfish: SilverStripe\Security\PasswordEncryptor_Blowfish + PasswordEncryptor_PHPHash: SilverStripe\Security\PasswordEncryptor_PHPHash + PasswordEncryptor_LegacyPHPHash: SilverStripe\Security\PasswordEncryptor_LegacyPHPHash + PasswordEncryptor_MySQLPassword: SilverStripe\Security\PasswordEncryptor_MySQLPassword + PasswordEncryptor_MySQLOldPassword: SilverStripe\Security\PasswordEncryptor_MySQLOldPassword + PasswordEncryptor_None: SilverStripe\Security\PasswordEncryptor_None + PasswordEncryptor_NotFoundException: SilverStripe\Security\PasswordEncryptor_NotFoundException + PasswordEncryptor_EncryptionFailed: SilverStripe\Security\PasswordEncryptor_EncryptionFailed + PasswordValidator: SilverStripe\Security\PasswordValidator + Permission: SilverStripe\Security\Permission + Permission_Group: SilverStripe\Security\Permission_Group + PermissionCheckboxSetField: SilverStripe\Security\PermissionCheckboxSetField + PermissionCheckboxSetField_Readonly: SilverStripe\Security\PermissionCheckboxSetField_Readonly + PermissionFailureException: SilverStripe\Security\PermissionFailureException + PermissionProvider: SilverStripe\Security\PermissionProvider + PermissionRole: SilverStripe\Security\PermissionRole + PermissionRoleCode: SilverStripe\Security\PermissionRoleCode + RandomGenerator: SilverStripe\Security\RandomGenerator + RememberLoginHash: SilverStripe\Security\RememberLoginHash + Security: SilverStripe\Security\Security + SecurityToken: SilverStripe\Security\SecurityToken + NullSecurityToken: SilverStripe\Security\NullSecurityToken skipConfigs: - db - casting - table_name - fixed_fields + - menu_title + - allowed_actions diff --git a/ORM/Connect/MySQLDatabase.php b/ORM/Connect/MySQLDatabase.php index bcbfcdec2..e747f62f2 100644 --- a/ORM/Connect/MySQLDatabase.php +++ b/ORM/Connect/MySQLDatabase.php @@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Connect; use Config; use Exception; use PaginatedList; +use SilverStripe\Framework\Core\Configurable; use SilverStripe\ORM\DataList; use SilverStripe\ORM\ArrayList; diff --git a/ORM/Connect/MySQLSchemaManager.php b/ORM/Connect/MySQLSchemaManager.php index abe238350..a8a880916 100644 --- a/ORM/Connect/MySQLSchemaManager.php +++ b/ORM/Connect/MySQLSchemaManager.php @@ -16,8 +16,10 @@ class MySQLSchemaManager extends DBSchemaManager { /** * Identifier for this schema, used for configuring schema-specific table * creation options + * + * @skipUpgrade */ - const ID = 'SilverStripe\ORM\Connect\MySQLDatabase'; + const ID = 'MySQLDatabase'; public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null) { $fieldSchemas = $indexSchemas = ""; diff --git a/ORM/DB.php b/ORM/DB.php index 586cfdd6c..137d9648b 100644 --- a/ORM/DB.php +++ b/ORM/DB.php @@ -9,7 +9,9 @@ use Config; use LogicException; use Cookie; use Injector; +use SilverStripe\ORM\Connect\DBConnector; use SilverStripe\ORM\Connect\DBSchemaManager; +use SilverStripe\ORM\Connect\SS_Query; use SilverStripe\ORM\Queries\SQLExpression; use SilverStripe\ORM\Connect\SS_Database; @@ -53,8 +55,8 @@ class DB { * Pass an object that's a subclass of SS_Database. This object will be used when {@link DB::query()} * is called. * - * @param $connection The connecton object to set as the connection. - * @param $name The name to give to this connection. If you omit this argument, the connection + * @param SS_Database $connection The connecton object to set as the connection. + * @param string $name The name to give to this connection. If you omit this argument, the connection * will be the default one used by the ORM. However, you can store other named connections to * be accessed through DB::get_conn($name). This is useful when you have an application that * needs to connect to more than one database. @@ -147,6 +149,7 @@ class DB { * * Note that the database will be set on the next request. * Set it to null to revert to the main database. + * @param string $name */ public static function set_alternative_database_name($name = null) { // Skip if CLI @@ -161,7 +164,7 @@ class DB { )); } - $key = Config::inst()->get('Security', 'token'); + $key = Config::inst()->get('SilverStripe\\Security\\Security', 'token'); if(!$key) { throw new LogicException('"Security.token" not found, run "sake dev/generatesecuretoken"'); } @@ -193,7 +196,7 @@ class DB { $iv = Cookie::get("alternativeDatabaseNameIv"); if($name) { - $key = Config::inst()->get('Security', 'token'); + $key = Config::inst()->get('SilverStripe\\Security\\Security', 'token'); if(!$key) { throw new LogicException('"Security.token" not found, run "sake dev/generatesecuretoken"'); } @@ -231,10 +234,9 @@ class DB { * Given the database configuration, this method will create the correct * subclass of {@link SS_Database}. * - * @param array $database A map of options. The 'type' is the name of the subclass of SS_Database to use. For the - * rest of the options, see the specific class. - * @param string $name identifier for the connection - * + * @param array $databaseConfig A map of options. The 'type' is the name of the + * subclass of SS_Database to use. For the rest of the options, see the specific class. + * @param string $label identifier for the connection * @return SS_Database */ public static function connect($databaseConfig, $label = 'default') { @@ -296,7 +298,7 @@ class DB { * * @param array|integer $input An array of items needing placeholders, or a * number to specify the number of placeholders - * @param string The string to join each placeholder together with + * @param string $join The string to join each placeholder together with * @return string|null Either a list of placeholders, or null */ public static function placeholders($input, $join = ', ') { @@ -374,6 +376,8 @@ class DB { /** * Get the autogenerated ID from the previous INSERT query. + * + * @param string $table * @return int */ public static function get_generated_id($table) { @@ -427,13 +431,14 @@ class DB { /** * Create a new table. - * @param string $tableName The name of the table + * @param string $table The name of the table * @param array$fields A map of field names to field types * @param array $indexes A map of indexes * @param array $options An map of additional options. The available keys are as follows: * - 'MSSQLDatabase'/'MySQLDatabase'/'PostgreSQLDatabase' - database-specific options such as "engine" * for MySQL. * - 'temporary' - If true, then a temporary table will be created + * @param array $advancedOptions * @return string The table name generated. This may be different from the table name, for example with * temporary tables. */ @@ -577,7 +582,7 @@ class DB { /** * Checks a table's integrity and repairs it if necessary. * - * @param string $tableName The name of the table. + * @param string $table The name of the table. * @return boolean Return true if the table has integrity after the method is complete. */ public static function check_and_repair_table($table) { diff --git a/ORM/DataObject.php b/ORM/DataObject.php index d059939b3..f6e4423cd 100644 --- a/ORM/DataObject.php +++ b/ORM/DataObject.php @@ -19,8 +19,8 @@ use SearchContext; use FieldList; use FormField; use FormScaffolder; -use Member; -use Permission; + + use Object; use SearchFilter; use SilverStripe\ORM\Queries\SQLInsert; @@ -30,6 +30,9 @@ use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBComposite; use SilverStripe\ORM\FieldType\DBClassName; +use SilverStripe\Security\Member; +use SilverStripe\Security\Permission; + /** * A single database record & abstract class for the data-access-model. @@ -907,10 +910,10 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity * Caution: Does not delete the merged object. * Caution: Does now overwrite Created date on the original object. * - * @param $obj DataObject - * @param $priority String left|right Determines who wins in case of a conflict (optional) - * @param $includeRelations Boolean Merge any existing relations (optional) - * @param $overwriteWithEmpty Boolean Overwrite existing left values with empty right values. + * @param DataObject $rightObj + * @param string $priority left|right Determines who wins in case of a conflict (optional) + * @param bool $includeRelations Merge any existing relations (optional) + * @param bool $overwriteWithEmpty Overwrite existing left values with empty right values. * Only applicable with $priority='right'. (optional) * @return Boolean */ diff --git a/ORM/DatabaseAdmin.php b/ORM/DatabaseAdmin.php index 5a83632c3..045a6addd 100644 --- a/ORM/DatabaseAdmin.php +++ b/ORM/DatabaseAdmin.php @@ -5,12 +5,15 @@ namespace SilverStripe\ORM; use Controller; use SapphireTest; use Director; -use Security; -use Permission; + + use SS_ClassLoader; use ClassInfo; use TestOnly; use Deprecation; +use SilverStripe\Security\Security; +use SilverStripe\Security\Permission; + // Include the DB class require_once("DB.php"); @@ -183,6 +186,7 @@ class DatabaseAdmin extends Controller { * * @param boolean $quiet Don't show messages * @param boolean $populate Populate the database, as well as setting up its schema + * @param bool $testMode */ public function doBuild($quiet = false, $populate = true, $testMode = false) { if($quiet) { diff --git a/ORM/FieldType/DBDate.php b/ORM/FieldType/DBDate.php index f6e552034..b7daea3c2 100644 --- a/ORM/FieldType/DBDate.php +++ b/ORM/FieldType/DBDate.php @@ -2,13 +2,15 @@ namespace SilverStripe\ORM\FieldType; -use Member; + use Zend_Date; use DateTime; use DateField; use Convert; use Exception; use SilverStripe\ORM\DB; +use SilverStripe\Security\Member; + /** * Represents a date field. diff --git a/ORM/FieldType/DBDatetime.php b/ORM/FieldType/DBDatetime.php index a924b19db..bab437f04 100644 --- a/ORM/FieldType/DBDatetime.php +++ b/ORM/FieldType/DBDatetime.php @@ -4,12 +4,13 @@ namespace SilverStripe\ORM\FieldType; use Convert; use Exception; -use Member; use DatetimeField; use Zend_Date; use TemplateGlobalProvider; use DateTime; use SilverStripe\ORM\DB; +use SilverStripe\Security\Member; + /** * Represents a date-time field. @@ -60,11 +61,11 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider { if(is_numeric($value)) { $this->value = date('Y-m-d H:i:s', $value); } elseif(is_string($value)) { - try { + try{ $date = new DateTime($value); $this->value = $date->format('Y-m-d H:i:s'); return; - } catch(Exception $e) { + }catch(Exception $e){ $this->value = null; return; } diff --git a/ORM/Hierarchy/Hierarchy.php b/ORM/Hierarchy/Hierarchy.php index 083afcbae..841df76b0 100644 --- a/ORM/Hierarchy/Hierarchy.php +++ b/ORM/Hierarchy/Hierarchy.php @@ -768,14 +768,15 @@ class Hierarchy extends DataExtension { * @return DataObject */ public function getParent($filter = null) { - if($p = $this->owner->__get("ParentID")) { - $tableClasses = ClassInfo::dataClassesFor($this->owner->class); - $baseClass = array_shift($tableClasses); - return DataObject::get_one($this->owner->class, array( - array("\"$baseClass\".\"ID\"" => $p), - $filter - )); + $parentID = $this->owner->ParentID; + if(empty($parentID)) { + return null; } + $idSQL = $this->owner->getSchema()->sqlColumnForField($this->owner, 'ID'); + return DataObject::get_one($this->owner->class, array( + array($idSQL => $parentID), + $filter + )); } /** diff --git a/ORM/Queries/SQLExpression.php b/ORM/Queries/SQLExpression.php index bb1075d53..bbd2cfe26 100644 --- a/ORM/Queries/SQLExpression.php +++ b/ORM/Queries/SQLExpression.php @@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Queries; use Exception; use Convert; +use SilverStripe\ORM\Connect\SS_Query; use SilverStripe\ORM\DB; /** diff --git a/ORM/Versioning/ChangeSet.php b/ORM/Versioning/ChangeSet.php index 59572b836..55cf5255e 100644 --- a/ORM/Versioning/ChangeSet.php +++ b/ORM/Versioning/ChangeSet.php @@ -2,9 +2,11 @@ namespace SilverStripe\ORM\Versioning; -use Member; -use Permission; + + +use Exception; use FieldList; +use SilverStripe\ORM\HasManyList; use TextField; use ReadonlyField; use i18n; @@ -13,6 +15,9 @@ use LogicException; use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\DB; use SilverStripe\ORM\DataObject; +use SilverStripe\Security\Member; +use SilverStripe\Security\Permission; + /** * The ChangeSet model tracks several VersionedAndStaged objects for later publication as a single @@ -57,7 +62,7 @@ class ChangeSet extends DataObject { ); private static $has_one = array( - 'Owner' => 'Member', + 'Owner' => 'SilverStripe\\Security\\Member', ); private static $casting = array( diff --git a/ORM/Versioning/ChangeSetItem.php b/ORM/Versioning/ChangeSetItem.php index 620247690..2ef13e05e 100644 --- a/ORM/Versioning/ChangeSetItem.php +++ b/ORM/Versioning/ChangeSetItem.php @@ -4,12 +4,18 @@ namespace SilverStripe\ORM\Versioning; use Exception; use BadMethodCallException; -use Member; -use Permission; + + use CMSPreviewable; use Controller; use SilverStripe\Filesystem\Thumbnail; +use SilverStripe\ORM\DataList; use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\ManyManyList; +use SilverStripe\ORM\SS_List; +use SilverStripe\Security\Member; +use SilverStripe\Security\Permission; + /** * A single line in a changeset diff --git a/ORM/Versioning/Versioned.php b/ORM/Versioning/Versioned.php index ff4112d93..3436149e4 100644 --- a/ORM/Versioning/Versioned.php +++ b/ORM/Versioning/Versioned.php @@ -2,16 +2,17 @@ namespace SilverStripe\ORM\Versioning; +use SS_HTTPRequest; use TemplateGlobalProvider; use Session; use Deprecation; use InvalidArgumentException; use Config; use LogicException; -use Member; + use ClassInfo; use Object; -use Permission; + use Director; use Cookie; use FieldList; @@ -25,6 +26,9 @@ use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\Queries\SQLSelect; use SilverStripe\ORM\Queries\SQLUpdate; +use SilverStripe\Security\Member; +use SilverStripe\Security\Permission; + /** * The Versioned extension allows your DataObjects to have several versions, @@ -235,8 +239,8 @@ class Versioned extends DataExtension implements TemplateGlobalProvider { * Amend freshly created DataQuery objects with versioned-specific * information. * - * @param SQLSelect - * @param DataQuery + * @param SQLSelect $query + * @param DataQuery $dataQuery */ public function augmentDataQueryCreation(SQLSelect &$query, DataQuery &$dataQuery) { $parts = explode('.', Versioned::get_reading_mode()); @@ -2397,7 +2401,7 @@ class Versioned extends DataExtension implements TemplateGlobalProvider { } /** - * @param FieldList + * @param FieldList $fields */ public function updateCMSFields(FieldList $fields) { // remove the version field from the CMS as this should be left diff --git a/security/Authenticator.php b/Security/Authenticator.php similarity index 92% rename from security/Authenticator.php rename to Security/Authenticator.php index de3619c82..dbb48b9b1 100644 --- a/security/Authenticator.php +++ b/Security/Authenticator.php @@ -1,4 +1,11 @@ update('BasicAuth', 'entire_site_protected', $protect); - Config::inst()->update('BasicAuth', 'entire_site_protected_code', $code); - Config::inst()->update('BasicAuth', 'entire_site_protected_message', $message); + Config::inst()->update('SilverStripe\\Security\\BasicAuth', 'entire_site_protected', $protect); + Config::inst()->update('SilverStripe\\Security\\BasicAuth', 'entire_site_protected_code', $code); + Config::inst()->update('SilverStripe\\Security\\BasicAuth', 'entire_site_protected_message', $message); } /** @@ -143,7 +153,7 @@ class BasicAuth { * please use {@link protect_entire_site()}. */ public static function protect_site_if_necessary() { - $config = Config::inst()->forClass('BasicAuth'); + $config = Config::inst()->forClass('SilverStripe\\Security\\BasicAuth'); if($config->entire_site_protected) { self::requireLogin($config->entire_site_protected_message, $config->entire_site_protected_code, false); } diff --git a/security/CMSMemberLoginForm.php b/Security/CMSMemberLoginForm.php similarity index 92% rename from security/CMSMemberLoginForm.php rename to Security/CMSMemberLoginForm.php index 379239421..caeef34a2 100644 --- a/security/CMSMemberLoginForm.php +++ b/Security/CMSMemberLoginForm.php @@ -1,5 +1,19 @@ performLogin($data)) { @@ -110,7 +125,7 @@ class CMSMemberLoginForm extends LoginForm { */ protected function redirectToChangePassword() { // Since this form is loaded via an iframe, this redirect must be performed via javascript - $changePasswordForm = new ChangePasswordForm($this->controller, 'ChangePasswordForm'); + $changePasswordForm = new ChangePasswordForm($this->controller, 'SilverStripe\\Security\\ChangePasswordForm'); $changePasswordForm->sessionMessage( _t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'), 'good' diff --git a/security/CMSSecurity.php b/Security/CMSSecurity.php similarity index 95% rename from security/CMSSecurity.php rename to Security/CMSSecurity.php index ae80a11bc..a58cffc51 100644 --- a/security/CMSSecurity.php +++ b/Security/CMSSecurity.php @@ -1,5 +1,16 @@ "Group", + "Parent" => "SilverStripe\\Security\\Group", ); private static $has_many = array( - "Permissions" => "Permission", - "Groups" => "Group" + "Permissions" => "SilverStripe\\Security\\Permission", + "Groups" => "SilverStripe\\Security\\Group" ); private static $many_many = array( - "Members" => "Member", - "Roles" => "PermissionRole", + "Members" => "SilverStripe\\Security\\Member", + "Roles" => "SilverStripe\\Security\\PermissionRole", ); private static $extensions = array( "SilverStripe\\ORM\\Hierarchy\\Hierarchy", ); + private static $table_name = "Group"; + public function populateDefaults() { parent::populateDefaults(); @@ -61,7 +88,7 @@ class Group extends DataObject { public function getAllChildren() { $doSet = new ArrayList(); - $children = DataObject::get('Group')->filter("ParentID", $this->ID); + $children = Group::get()->filter("ParentID", $this->ID); foreach($children as $child) { $doSet->push($child); $doSet->merge($child->getAllChildren()); @@ -94,7 +121,7 @@ class Group extends DataObject { $permissionsField = new PermissionCheckboxSetField( 'Permissions', false, - 'Permission', + 'SilverStripe\\Security\\Permission', 'GroupID', $this ) @@ -163,7 +190,7 @@ class Group extends DataObject { // Only show the "Roles" tab if permissions are granted to edit them, // and at least one role exists - if(Permission::check('APPLY_ROLES') && DataObject::get('PermissionRole')) { + if(Permission::check('APPLY_ROLES') && DataObject::get('SilverStripe\\Security\\PermissionRole')) { $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.ROLES', 'Roles')); $fields->addFieldToTab('Root.Roles', new LiteralField( @@ -223,9 +250,8 @@ class Group extends DataObject { } /** - * - * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields - * + * @param bool $includerelations Indicate if the labels returned include relation fields + * @return array */ public function fieldLabels($includerelations = true) { $labels = parent::fieldLabels($includerelations); @@ -358,7 +384,7 @@ class Group extends DataObject { $inheritedCodes = Permission::get() ->filter('GroupID', $this->Parent()->collateAncestorIDs()) ->column('Code'); - $privilegedCodes = Config::inst()->get('Permission', 'privileged_permissions'); + $privilegedCodes = Config::inst()->get('SilverStripe\\Security\\Permission', 'privileged_permissions'); if(array_intersect($inheritedCodes, $privilegedCodes)) { $result->error(sprintf( _t( @@ -406,7 +432,7 @@ class Group extends DataObject { * @return boolean */ public function canEdit($member = null) { - if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser(); + if(!$member || !(is_a($member, 'SilverStripe\\Security\\Member')) || is_numeric($member)) $member = Member::currentUser(); // extended access checks $results = $this->extend('canEdit', $member); @@ -436,7 +462,7 @@ class Group extends DataObject { * @return boolean */ public function canView($member = null) { - if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser(); + if(!$member || !(is_a($member, 'SilverStripe\\Security\\Member')) || is_numeric($member)) $member = Member::currentUser(); // extended access checks $results = $this->extend('canView', $member); @@ -449,7 +475,7 @@ class Group extends DataObject { } public function canDelete($member = null) { - if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser(); + if(!$member || !(is_a($member, 'SilverStripe\\Security\\Member')) || is_numeric($member)) $member = Member::currentUser(); // extended access checks $results = $this->extend('canDelete', $member); @@ -487,7 +513,7 @@ class Group extends DataObject { parent::requireDefaultRecords(); // Add default author group if no other group exists - $allGroups = DataObject::get('Group'); + $allGroups = DataObject::get('SilverStripe\\Security\\Group'); if(!$allGroups->count()) { $authorGroup = new Group(); $authorGroup->Code = 'content-authors'; diff --git a/security/GroupCsvBulkLoader.php b/Security/GroupCsvBulkLoader.php similarity index 85% rename from security/GroupCsvBulkLoader.php rename to Security/GroupCsvBulkLoader.php index 3f23b4aae..70636d2e7 100644 --- a/security/GroupCsvBulkLoader.php +++ b/Security/GroupCsvBulkLoader.php @@ -1,6 +1,11 @@ Arg and Permission->Type values * @@ -14,7 +19,7 @@ class GroupCsvBulkLoader extends CsvBulkLoader { ); public function __construct($objectClass = null) { - if(!$objectClass) $objectClass = 'Group'; + if(!$objectClass) $objectClass = 'SilverStripe\\Security\\Group'; parent::__construct($objectClass); } @@ -30,7 +35,7 @@ class GroupCsvBulkLoader extends CsvBulkLoader { // are imported to avoid missing "early" references to parents // which are imported later on in the CSV file. if(isset($record['ParentCode']) && $record['ParentCode']) { - $parentGroup = DataObject::get_one('Group', array( + $parentGroup = DataObject::get_one('SilverStripe\\Security\\Group', array( '"Group"."Code"' => $record['ParentCode'] )); if($parentGroup) { @@ -43,7 +48,7 @@ class GroupCsvBulkLoader extends CsvBulkLoader { // existing permissions arent cleared. if(isset($record['PermissionCodes']) && $record['PermissionCodes']) { foreach(explode(',', $record['PermissionCodes']) as $code) { - $p = DataObject::get_one('Permission', array( + $p = DataObject::get_one('SilverStripe\\Security\\Permission', array( '"Permission"."Code"' => $code, '"Permission"."GroupID"' => $group->ID )); diff --git a/security/LoginAttempt.php b/Security/LoginAttempt.php similarity index 81% rename from security/LoginAttempt.php rename to Security/LoginAttempt.php index 70e4cd830..e0e4cfe67 100644 --- a/security/LoginAttempt.php +++ b/Security/LoginAttempt.php @@ -1,6 +1,11 @@ 'Member', // only linked if the member actually exists + 'Member' => 'SilverStripe\\Security\\Member', // only linked if the member actually exists ); - private static $has_many = array(); - - private static $many_many = array(); - - private static $belongs_many_many = array(); + private static $table_name = "LoginAttempt"; /** - * - * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields - * + * @param bool $includerelations Indicate if the labels returned include relation fields + * @return array */ public function fieldLabels($includerelations = true) { $labels = parent::fieldLabels($includerelations); diff --git a/security/LoginForm.php b/Security/LoginForm.php similarity index 90% rename from security/LoginForm.php rename to Security/LoginForm.php index dbc047ec7..c8f2151a8 100644 --- a/security/LoginForm.php +++ b/Security/LoginForm.php @@ -1,4 +1,10 @@ authenticator_class) || !is_subclass_of($this->authenticator_class, 'Authenticator')) { + if(!class_exists($this->authenticator_class) || !is_subclass_of($this->authenticator_class, 'SilverStripe\\Security\\Authenticator')) { user_error("The form uses an invalid authenticator class! '{$this->authenticator_class}'" . " is not a subclass of 'Authenticator'", E_USER_ERROR); return; diff --git a/security/Member.php b/Security/Member.php similarity index 92% rename from security/Member.php rename to Security/Member.php index dfad94a41..85534a58f 100644 --- a/security/Member.php +++ b/Security/Member.php @@ -1,6 +1,8 @@ 'Group', + 'Groups' => 'SilverStripe\\Security\\Group', ); - private static $has_one = array(); - private static $has_many = array( - 'LoggedPasswords' => 'MemberPassword', - 'RememberLoginHashes' => 'RememberLoginHash' + 'LoggedPasswords' => 'SilverStripe\\Security\\MemberPassword', + 'RememberLoginHashes' => 'SilverStripe\\Security\\RememberLoginHash' ); - private static $many_many = array(); - - private static $many_many_extraFields = array(); + private static $table_name = "Member"; private static $default_sort = '"Surname", "FirstName"'; @@ -133,7 +154,7 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * @config - * @var Array See {@link set_title_columns()} + * @var array See {@link set_title_columns()} */ private static $title_format = null; @@ -148,8 +169,10 @@ class Member extends DataObject implements TemplateGlobalProvider { private static $unique_identifier_field = 'Email'; /** + * Object for validating user's password + * * @config - * {@link PasswordValidator} object for validating user's password + * @var PasswordValidator */ private static $password_validator = null; @@ -243,8 +266,8 @@ class Member extends DataObject implements TemplateGlobalProvider { if(!Security::has_default_admin()) return null; // Find or create ADMIN group - singleton('Group')->requireDefaultRecords(); - $adminGroup = Permission::get_groups_by_permission('ADMIN')->First(); + Group::singleton()->requireDefaultRecords(); + $adminGroup = Permission::get_groups_by_permission('ADMIN')->first(); // Find member $admin = Member::get() @@ -423,6 +446,8 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * Set a {@link PasswordValidator} object to use to validate member's passwords. + * + * @param PasswordValidator $pv */ public static function set_password_validator($pv) { self::$password_validator = $pv; @@ -430,6 +455,8 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * Returns the current {@link PasswordValidator} + * + * @return PasswordValidator */ public static function password_validator() { return self::$password_validator; @@ -482,8 +509,8 @@ class Member extends DataObject implements TemplateGlobalProvider { } if($remember) { $rememberLoginHash = RememberLoginHash::generate($this); - $tokenExpiryDays = Config::inst()->get('RememberLoginHash', 'token_expiry_days'); - $deviceExpiryDays = Config::inst()->get('RememberLoginHash', 'device_expiry_days'); + $tokenExpiryDays = Config::inst()->get('SilverStripe\\Security\\RememberLoginHash', 'token_expiry_days'); + $deviceExpiryDays = Config::inst()->get('SilverStripe\\Security\\RememberLoginHash', 'device_expiry_days'); Cookie::set('alc_enc', $this->ID . ':' . $rememberLoginHash->getToken(), $tokenExpiryDays, null, null, null, true); Cookie::set('alc_device', $rememberLoginHash->DeviceID, $deviceExpiryDays, null, null, null, true); @@ -497,10 +524,7 @@ class Member extends DataObject implements TemplateGlobalProvider { // Clear the incorrect log-in count $this->registerSuccessfulLogin(); - // Don't set column if its not built yet (the login might be precursor to a /dev/build...) - if(array_key_exists('LockedOutUntil', DB::field_list('Member'))) { - $this->LockedOutUntil = null; - } + $this->LockedOutUntil = null; $this->regenerateTempID(); @@ -534,7 +558,7 @@ class Member extends DataObject implements TemplateGlobalProvider { */ public static function logged_in_session_exists() { if($id = Member::currentUserID()) { - if($member = DataObject::get_by_id('Member', $id)) { + if($member = DataObject::get_by_id('SilverStripe\\Security\\Member', $id)) { if($member->exists()) return true; } } @@ -570,7 +594,7 @@ class Member extends DataObject implements TemplateGlobalProvider { $deviceID = Cookie::get('alc_device'); - $member = Member::get()->byId($uid); + $member = Member::get()->byID($uid); $rememberLoginHash = null; @@ -606,7 +630,7 @@ class Member extends DataObject implements TemplateGlobalProvider { if ($rememberLoginHash) { $rememberLoginHash->renew(); - $tokenExpiryDays = Config::inst()->get('RememberLoginHash', 'token_expiry_days'); + $tokenExpiryDays = Config::inst()->get('SilverStripe\\Security\\RememberLoginHash', 'token_expiry_days'); Cookie::set('alc_enc', $member->ID . ':' . $rememberLoginHash->getToken(), $tokenExpiryDays, null, null, false, true); } @@ -652,6 +676,10 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * Utility for generating secure password hashes for this member. + * + * @param string $string + * @return string + * @throws PasswordEncryptor_NotFoundException */ public function encryptWithUserSettings($string) { if (!$string) return null; @@ -683,7 +711,7 @@ class Member extends DataObject implements TemplateGlobalProvider { $generator = new RandomGenerator(); $token = $generator->randomToken(); $hash = $this->encryptWithUserSettings($token); - } while(DataObject::get_one('Member', array( + } while(DataObject::get_one('SilverStripe\\Security\\Member', array( '"Member"."AutoLoginHash"' => $hash ))); @@ -720,7 +748,7 @@ class Member extends DataObject implements TemplateGlobalProvider { public static function member_from_autologinhash($hash, $login = false) { $nowExpression = DB::get_conn()->now(); - $member = DataObject::get_one('Member', array( + $member = DataObject::get_one('SilverStripe\\Security\\Member', array( "\"Member\".\"AutoLoginHash\"" => $hash, "\"Member\".\"AutoLoginExpired\" > $nowExpression" // NOW() can't be parameterised )); @@ -815,7 +843,7 @@ class Member extends DataObject implements TemplateGlobalProvider { * @return Member_Validator */ public function getValidator() { - $validator = Injector::inst()->create('Member_Validator'); + $validator = Injector::inst()->create('SilverStripe\\Security\\Member_Validator'); $validator->setForMember($this); $this->extend('updateValidator', $validator); @@ -826,13 +854,13 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * Returns the current logged in user * - * @return Member|null + * @return Member */ public static function currentUser() { $id = Member::currentUserID(); if($id) { - return Member::get()->byId($id); + return Member::get()->byID($id); } } @@ -860,7 +888,7 @@ class Member extends DataObject implements TemplateGlobalProvider { * @return string Returns a random password. */ public static function create_new_password() { - $words = Config::inst()->get('Security', 'word_list'); + $words = Config::inst()->get('SilverStripe\\Security\\Security', 'word_list'); if($words && file_exists($words)) { $words = file($words); @@ -897,7 +925,7 @@ class Member extends DataObject implements TemplateGlobalProvider { if($this->ID) { $filter[] = array('"Member"."ID" <> ?' => $this->ID); } - $existingRecord = DataObject::get_one('Member', $filter); + $existingRecord = DataObject::get_one('SilverStripe\\Security\\Member', $filter); if($existingRecord) { throw new ValidationException(ValidationResult::create(false, _t( @@ -1001,8 +1029,8 @@ class Member extends DataObject implements TemplateGlobalProvider { * Filter out admin groups to avoid privilege escalation, * If any admin groups are requested, deny the whole save operation. * - * @param Array $ids Database IDs of Group records - * @return boolean True if the change can be accepted + * @param array $ids Database IDs of Group records + * @return bool True if the change can be accepted */ public function onChangeGroups($ids) { // unless the current user is an admin already OR the logged in user is an admin @@ -1042,9 +1070,9 @@ class Member extends DataObject implements TemplateGlobalProvider { */ public function inGroup($group, $strict = false) { if(is_numeric($group)) { - $groupCheckObj = DataObject::get_by_id('Group', $group); + $groupCheckObj = DataObject::get_by_id('SilverStripe\\Security\\Group', $group); } elseif(is_string($group)) { - $groupCheckObj = DataObject::get_one('Group', array( + $groupCheckObj = DataObject::get_one('SilverStripe\\Security\\Group', array( '"Group"."Code"' => $group )); } elseif($group instanceof Group) { @@ -1068,10 +1096,10 @@ class Member extends DataObject implements TemplateGlobalProvider { * group code does not return a valid group object. * * @param string $groupcode - * @param string Title of the group + * @param string $title Title of the group */ public function addToGroupByCode($groupcode, $title = "") { - $group = DataObject::get_one('Group', array( + $group = DataObject::get_one('SilverStripe\\Security\\Group', array( '"Group"."Code"' => $groupcode )); @@ -1103,7 +1131,7 @@ class Member extends DataObject implements TemplateGlobalProvider { } /** - * @param Array $columns Column names on the Member record to show in {@link getTitle()}. + * @param array $columns Column names on the Member record to show in {@link getTitle()}. * @param String $sep Separator */ public static function set_title_columns($columns, $sep = ' ') { @@ -1151,24 +1179,28 @@ class Member extends DataObject implements TemplateGlobalProvider { * Return a SQL CONCAT() fragment suitable for a SELECT statement. * Useful for custom queries which assume a certain member title format. * - * @param String $tableName * @return String SQL */ - public static function get_title_sql($tableName = 'Member') { + public static function get_title_sql() { // This should be abstracted to SSDatabase concatOperator or similar. $op = (DB::get_conn() instanceof MSSQLDatabase) ? " + " : " || "; - $format = self::config()->title_format; - if ($format) { - $columnsWithTablename = array(); - foreach($format['columns'] as $column) { - $columnsWithTablename[] = "\"$tableName\".\"$column\""; - } - - return "(".join(" $op '".$format['sep']."' $op ", $columnsWithTablename).")"; - } else { - return "(\"$tableName\".\"Surname\" $op ' ' $op \"$tableName\".\"FirstName\")"; + // Get title_format with fallback to default + $format = static::config()->title_format; + if (!$format) { + $format = [ + 'columns' => ['Surname', 'FirstName'], + 'sep' => ' ', + ]; } + + $columnsWithTablename = array(); + foreach($format['columns'] as $column) { + $columnsWithTablename[] = static::getSchema()->sqlColumnForField(__CLASS__, $column); + } + + $sepSQL = \Convert::raw2sql($format['sep'], true); + return "(".join(" $op $sepSQL $op ", $columnsWithTablename).")"; } @@ -1249,7 +1281,7 @@ class Member extends DataObject implements TemplateGlobalProvider { * @return Member_Groupset */ public function Groups() { - $groups = Member_GroupSet::create('Group', 'Group_Members', 'GroupID', 'MemberID'); + $groups = Member_GroupSet::create('SilverStripe\\Security\\Group', 'Group_Members', 'GroupID', 'MemberID'); $groups = $groups->forForeignID($this->ID); $this->extend('updateGroups', $groups); @@ -1326,7 +1358,8 @@ class Member extends DataObject implements TemplateGlobalProvider { } $permsClause = DB::placeholders($perms); - $groups = DataObject::get('Group') + /** @skipUpgrade */ + $groups = DataObject::get('SilverStripe\\Security\\Group') ->innerJoin("Permission", '"Permission"."GroupID" = "Group"."ID"') ->where(array( "\"Permission\".\"Code\" IN ($permsClause)" => $perms @@ -1343,6 +1376,7 @@ class Member extends DataObject implements TemplateGlobalProvider { $groupIDList = $groups; } + /** @skipUpgrade */ $members = Member::get() ->innerJoin("Group_Members", '"Group_Members"."MemberID" = "Member"."ID"') ->innerJoin("Group", '"Group"."ID" = "Group_Members"."GroupID"'); @@ -1429,7 +1463,7 @@ class Member extends DataObject implements TemplateGlobalProvider { } asort($groupsMap); $fields->addFieldToTab('Root.Main', - ListboxField::create('DirectGroups', singleton('Group')->i18n_plural_name()) + ListboxField::create('DirectGroups', singleton('SilverStripe\\Security\\Group')->i18n_plural_name()) ->setSource($groupsMap) ->setAttribute( 'data-placeholder', @@ -1445,12 +1479,12 @@ class Member extends DataObject implements TemplateGlobalProvider { $permissionsField = new PermissionCheckboxSetField_Readonly( 'Permissions', false, - 'Permission', + 'SilverStripe\\Security\\Permission', 'GroupID', // we don't want parent relationships, they're automatically resolved in the field $self->getManyManyComponents('Groups') ); - $fields->findOrMakeTab('Root.Permissions', singleton('Permission')->i18n_plural_name()); + $fields->findOrMakeTab('Root.Permissions', singleton('SilverStripe\\Security\\Permission')->i18n_plural_name()); $fields->addFieldToTab('Root.Permissions', $permissionsField); } } @@ -1499,9 +1533,8 @@ class Member extends DataObject implements TemplateGlobalProvider { } /** - * - * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields - * + * @param bool $includerelations Indicate if the labels returned include relation fields + * @return array */ public function fieldLabels($includerelations = true) { $labels = parent::fieldLabels($includerelations); @@ -1522,11 +1555,14 @@ class Member extends DataObject implements TemplateGlobalProvider { return $labels; } - /** - * Users can view their own record. - * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions. - * This is likely to be customized for social sites etc. with a looser permission model. - */ + /** + * Users can view their own record. + * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions. + * This is likely to be customized for social sites etc. with a looser permission model. + * + * @param Member $member + * @return bool + */ public function canView($member = null) { //get member if(!($member instanceof Member)) { @@ -1549,10 +1585,14 @@ class Member extends DataObject implements TemplateGlobalProvider { //standard check return Permission::checkMember($member, 'CMS_ACCESS_SecurityAdmin'); } - /** - * Users can edit their own record. - * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions - */ + + /** + * Users can edit their own record. + * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions + * + * @param Member $member + * @return bool + */ public function canEdit($member = null) { //get member if(!($member instanceof Member)) { @@ -1583,6 +1623,9 @@ class Member extends DataObject implements TemplateGlobalProvider { /** * Users can edit their own record. * Otherwise they'll need ADMIN or CMS_ACCESS_SecurityAdmin permissions + * + * @param Member $member + * @return bool */ public function canDelete($member = null) { if(!($member instanceof Member)) { @@ -1641,7 +1684,8 @@ class Member extends DataObject implements TemplateGlobalProvider { * Change password. This will cause rehashing according to * the `PasswordEncryption` property. * - * @param String $password Cleartext password + * @param string $password Cleartext password + * @return ValidationResult */ public function changePassword($password) { $this->Password = $password; @@ -1755,7 +1799,7 @@ class Member_GroupSet extends ManyManyList { $allGroupIDs = array(); while($groupIDs) { $allGroupIDs = array_merge($allGroupIDs, $groupIDs); - $groupIDs = DataObject::get("Group")->byIDs($groupIDs)->column("ParentID"); + $groupIDs = DataObject::get("SilverStripe\\Security\\Group")->byIDs($groupIDs)->column("ParentID"); $groupIDs = array_filter($groupIDs); } @@ -1811,7 +1855,7 @@ class Member_GroupSet extends ManyManyList { protected function getMember() { $id = $this->getForeignID(); if($id) { - return DataObject::get_by_id('Member', $id); + return DataObject::get_by_id('SilverStripe\\Security\\Member', $id); } } } diff --git a/security/MemberAuthenticator.php b/Security/MemberAuthenticator.php similarity index 95% rename from security/MemberAuthenticator.php rename to Security/MemberAuthenticator.php index 27bdbb61d..708a7a21f 100644 --- a/security/MemberAuthenticator.php +++ b/Security/MemberAuthenticator.php @@ -1,6 +1,14 @@ extend('authenticationFailedUnknownUser', $data); + Member::singleton()->extend('authenticationFailedUnknownUser', $data); } } @@ -170,16 +178,18 @@ class MemberAuthenticator extends Authenticator { /** * Method that creates the login form for this authentication method * - * @param Controller The parent controller, necessary to create the + * @param Controller $controller The parent controller, necessary to create the * appropriate form action tag * @return Form Returns the login form to use with this authentication * method */ public static function get_login_form(Controller $controller) { + /** @skipUpgrade */ return MemberLoginForm::create($controller, "LoginForm"); } public static function get_cms_login_form(\Controller $controller) { + /** @skipUpgrade */ return CMSMemberLoginForm::create($controller, "LoginForm"); } diff --git a/security/MemberCsvBulkLoader.php b/Security/MemberCsvBulkLoader.php similarity index 90% rename from security/MemberCsvBulkLoader.php rename to Security/MemberCsvBulkLoader.php index a002e4d13..0cfdf1f6e 100644 --- a/security/MemberCsvBulkLoader.php +++ b/Security/MemberCsvBulkLoader.php @@ -1,6 +1,12 @@ groups = $groups; } /** - * @return Array + * @return array */ public function getGroups() { return $this->groups; diff --git a/security/MemberLoginForm.php b/Security/MemberLoginForm.php similarity index 93% rename from security/MemberLoginForm.php rename to Security/MemberLoginForm.php index 1194250d4..1dc376509 100644 --- a/security/MemberLoginForm.php +++ b/Security/MemberLoginForm.php @@ -1,4 +1,24 @@ fieldLabel(Member::config()->unique_identifier_field); + $label=singleton('SilverStripe\\Security\\Member')->fieldLabel(Member::config()->unique_identifier_field); $fields = FieldList::create( HiddenField::create("AuthenticationMethod", null, $this->authenticator_class, $this), // Regardless of what the unique identifer field is (usually 'Email'), it will be held in the @@ -99,7 +118,7 @@ class MemberLoginForm extends LoginForm { 'title', sprintf( _t('Member.REMEMBERME', "Remember me next time? (for %d days on this device)"), - Config::inst()->get('RememberLoginHash', 'token_expiry_days') + Config::inst()->get('SilverStripe\\Security\\RememberLoginHash', 'token_expiry_days') ) ) ); @@ -212,7 +231,7 @@ JS; if(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) { Session::set('BackURL', $backURL); } - $cp = ChangePasswordForm::create($this->controller, 'ChangePasswordForm'); + $cp = ChangePasswordForm::create($this->controller, 'SilverStripe\\Security\\ChangePasswordForm'); $cp->sessionMessage( _t('Member.PASSWORDEXPIRED', 'Your password has expired. Please choose a new one.'), 'good' @@ -275,7 +294,7 @@ JS; /** * Try to authenticate the user * - * @param array Submitted data + * @param array $data Submitted data * @return Member Returns the member object on successful authentication * or NULL on failure. */ @@ -300,6 +319,7 @@ JS; * in the form detailing why the action was denied. * * @param array $data Submitted data + * @return SS_HTTPResponse */ public function forgotPassword($data) { // Ensure password is given diff --git a/security/MemberPassword.php b/Security/MemberPassword.php similarity index 89% rename from security/MemberPassword.php rename to Security/MemberPassword.php index 60f2ec102..b7d82df76 100644 --- a/security/MemberPassword.php +++ b/Security/MemberPassword.php @@ -1,6 +1,11 @@ 'Member' + 'Member' => 'SilverStripe\\Security\\Member' ); - - private static $has_many = array(); - - private static $many_many = array(); - - private static $belongs_many_many = array(); + + private static $table_name = "MemberPassword"; /** * Log a password change from the given member. * Call MemberPassword::log($this) from within Member whenever the password is changed. + * + * @param Member $member */ public static function log($member) { $record = new MemberPassword(); diff --git a/security/PasswordEncryptor.php b/Security/PasswordEncryptor.php similarity index 94% rename from security/PasswordEncryptor.php rename to Security/PasswordEncryptor.php index c22440b5f..3344f5beb 100644 --- a/security/PasswordEncryptor.php +++ b/Security/PasswordEncryptor.php @@ -1,6 +1,13 @@ get('PasswordEncryptor', 'encryptors'); + return Config::inst()->get('SilverStripe\\Security\\PasswordEncryptor', 'encryptors'); } /** @@ -73,9 +80,9 @@ abstract class PasswordEncryptor { * * @uses RandomGenerator * - * @param String $password Cleartext password + * @param string $password Cleartext password * @param Member $member (Optional) - * @return String Maximum of 50 characters + * @return string Maximum of 50 characters */ public function salt($password, $member = null) { $generator = new RandomGenerator(); @@ -87,6 +94,12 @@ abstract class PasswordEncryptor { * but is necessary for retain compatibility with password hashed * with flawed algorithms - see {@link PasswordEncryptor_LegacyPHPHash} and * {@link PasswordEncryptor_Blowfish} + * + * @param string $hash + * @param string $password + * @param string $salt + * @param Member $member + * @return bool */ public function check($hash, $password, $salt = null, $member = null) { return $hash === $this->encrypt($password, $salt, $member); @@ -129,8 +142,7 @@ class PasswordEncryptor_Blowfish extends PasswordEncryptor { /** * Gets the cost that is set for the blowfish algorithm * - * @param int $cost - * @return null + * @return int */ public static function get_cost() { return self::$cost; @@ -242,6 +254,10 @@ class PasswordEncryptor_Blowfish extends PasswordEncryptor { /** * self::$cost param is forced to be two digits with leading zeroes for ints 4-9 + * + * @param string $password + * @param Member $member + * @return string */ public function salt($password, $member = null) { $generator = new RandomGenerator(); @@ -274,7 +290,8 @@ class PasswordEncryptor_PHPHash extends PasswordEncryptor { protected $algorithm = 'sha1'; /** - * @param String $algorithm A PHP built-in hashing algorithm as defined by hash_algos() + * @param string $algorithm A PHP built-in hashing algorithm as defined by hash_algos() + * @throws Exception */ public function __construct($algorithm) { if(!in_array($algorithm, hash_algos())) { diff --git a/security/PasswordValidator.php b/Security/PasswordValidator.php similarity index 98% rename from security/PasswordValidator.php rename to Security/PasswordValidator.php index 0637347b2..70be2f7a2 100644 --- a/security/PasswordValidator.php +++ b/Security/PasswordValidator.php @@ -1,6 +1,11 @@ "Int", "Type" => "Int(1)" ); + private static $has_one = array( - "Group" => "Group" + "Group" => "SilverStripe\\Security\\Group" ); + private static $indexes = array( "Code" => true ); + private static $defaults = array( "Type" => 1 ); - private static $has_many = array(); - private static $many_many = array(); - - private static $belongs_many_many = array(); + private static $table_name = "Permission"; /** * This is the value to use for the "Type" field if a permission should be @@ -63,7 +71,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { * Method to globally disable "strict" checking, which means a permission * will be granted if the key does not exist at all. * - * @var bool + * @var array */ private static $declared_permissions = null; @@ -172,10 +180,14 @@ class Permission extends DataObject implements TemplateGlobalProvider { } // Turn the code into an array as we may need to add other permsissions to the set we check - if(!is_array($code)) $code = array($code); + if(!is_array($code)) { + $code = array($code); + } + + // Check if admin should be treated as holding all permissions + $adminImpliesAll = (bool)static::config()->admin_implies_all; if($arg == 'any') { - $adminImpliesAll = (bool)Config::inst()->get('Permission', 'admin_implies_all'); // Cache the permissions in memory if(!isset(self::$cache_permissions[$memberID])) { self::$cache_permissions[$memberID] = self::permissions_for_member($memberID); @@ -208,8 +220,8 @@ class Permission extends DataObject implements TemplateGlobalProvider { // Code filters $codeParams = is_array($code) ? $code : array($code); $codeClause = DB::placeholders($codeParams); - $adminParams = (self::$admin_implies_all) ? array('ADMIN') : array(); - $adminClause = (self::$admin_implies_all) ? ", ?" : ''; + $adminParams = $adminImpliesAll ? array('ADMIN') : array(); + $adminClause = $adminImpliesAll ? ", ?" : ''; // The following code should only be used if you're not using the "any" arg. This is kind // of obselete functionality and could possibly be deprecated. @@ -235,7 +247,6 @@ class Permission extends DataObject implements TemplateGlobalProvider { user_error("Permission::checkMember: bad arg '$arg'", E_USER_ERROR); } } - $adminFilter = (Config::inst()->get('Permission', 'admin_implies_all')) ? ",'ADMIN'" : ''; // Raw SQL for efficiency $permission = DB::prepared_query( @@ -259,7 +270,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { if($permission) return $permission; // Strict checking disabled? - if(!Config::inst()->get('Permission', 'strict_checking') || !$strict) { + if(!static::config()->strict_checking || !$strict) { $hasPermission = DB::prepared_query( "SELECT COUNT(*) FROM \"Permission\" @@ -270,7 +281,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { array_merge($codeParams, array(self::GRANT_PERMISSION)) )->value(); - if(!$hasPermission) return; + if(!$hasPermission) return false; } return false; @@ -279,6 +290,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { /** * Get all the 'any' permission codes available to the given member. * + * @param int $memberID * @return array */ public static function permissions_for_member($memberID) { @@ -332,7 +344,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { if($member && isset($_SESSION['Permission_groupList'][$member->ID])) return $_SESSION['Permission_groupList'][$member->ID]; } else { - $member = DataObject::get_by_id("Member", $memberID); + $member = DataObject::get_by_id("SilverStripe\\Security\\Member", $memberID); } if($member) { @@ -364,7 +376,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { * * @param int $groupID The ID of the group * @param string $code The permission code - * @param string Optional: The permission argument (e.g. a page ID). + * @param string $arg Optional: The permission argument (e.g. a page ID). * @returns Permission Returns the new permission object. */ public static function grant($groupID, $code, $arg = "any") { @@ -379,6 +391,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { break; case "all": $perm->Arg = -1; + break; default: if(is_numeric($arg)) { $perm->Arg = $arg; @@ -398,7 +411,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { * * @param int $groupID The ID of the group * @param string $code The permission code - * @param string Optional: The permission argument (e.g. a page ID). + * @param string $arg Optional: The permission argument (e.g. a page ID). * @returns Permission Returns the new permission object. */ public static function deny($groupID, $code, $arg = "any") { @@ -413,6 +426,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { break; case "all": $perm->Arg = -1; + break; default: if(is_numeric($arg)) { $perm->Arg = $arg; @@ -448,6 +462,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { if(empty($groupIDs)) return new ArrayList(); $groupClause = DB::placeholders($groupIDs); + /** @skipUpgrade */ $members = Member::get() ->where(array("\"Group\".\"ID\" IN ($groupClause)" => $groupIDs)) ->leftJoin("Group_Members", '"Member"."ID" = "Group_Members"."MemberID"') @@ -458,7 +473,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { /** * Return all of the groups that have one of the given permission codes - * @param $codes array|string Either a single permission code, or an array of permission codes + * @param array|string $codes Either a single permission code, or an array of permission codes * @return SS_List The matching group objects */ public static function get_groups_by_permission($codes) { @@ -466,7 +481,8 @@ class Permission extends DataObject implements TemplateGlobalProvider { $codeClause = DB::placeholders($codeParams); // Via Roles are groups that have the permission via a role - return DataObject::get('Group') + /** @skipUpgrade */ + return Group::get() ->where(array( "\"PermissionRoleCode\".\"Code\" IN ($codeClause) OR \"Permission\".\"Code\" IN ($codeClause)" => array_merge($codeParams, $codeParams) @@ -491,7 +507,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { * suitable for using in an interface. */ public static function get_codes($grouped = true) { - $classes = ClassInfo::implementorsOf('PermissionProvider'); + $classes = ClassInfo::implementorsOf('SilverStripe\\Security\\PermissionProvider'); $allCodes = array(); $adminCategory = _t('Permission.AdminGroup', 'Administrator'); @@ -571,6 +587,9 @@ class Permission extends DataObject implements TemplateGlobalProvider { /** * Sort permissions based on their sort value, or name * + * @param array $a + * @param array $b + * @return int */ public static function sort_permissions($a, $b) { if ($a['sort'] == $b['sort']) { @@ -582,48 +601,6 @@ class Permission extends DataObject implements TemplateGlobalProvider { } } - /** - * add a permission represented by the $code to the {@link slef::$hidden_permissions} list - * - * @deprecated 4.0 Use "Permission.hidden_permissions" config setting instead - * @param $code string - the permissions code - * @return void - */ - public static function add_to_hidden_permissions($code){ - if(is_string($codes)) $codes = array($codes); - Deprecation::notice('4.0', 'Use "Permission.hidden_permissions" config setting instead'); - Config::inst()->update('Permission', 'hidden_permissions', $codes); - } - - /** - * remove a permission represented by the $code from the {@link slef::$hidden_permissions} list - * - * @deprecated 4.0 Use "Permission.hidden_permissions" config setting instead - * @param $code string - the permissions code - * @return void - */ - public static function remove_from_hidden_permissions($code){ - if(is_string($codes)) $codes = array($codes); - Deprecation::notice('4.0', 'Use "Permission.hidden_permissions" config setting instead'); - Config::inst()->remove('Permission', 'hidden_permissions', $codes); - } - - /** - * Declare an array of permissions for the system. - * - * Permissions can be grouped by nesting arrays. Scalar values are always - * treated as permissions. - * - * @deprecated 4.0 Use "Permission.declared_permissions" config setting instead - * @param array $permArray A (possibly nested) array of permissions to - * declare for the system. - */ - public static function declare_permissions($permArray) { - Deprecation::notice('4.0', 'Use "Permission.declared_permissions" config setting instead'); - self::config()->declared_permissions = $permArray; - } - - /** * Get a linear list of the permissions in the system. * @@ -638,8 +615,7 @@ class Permission extends DataObject implements TemplateGlobalProvider { self::$declared_permissions_list = array(); - self::traverse_declared_permissions(self::$declared_permissions, - self::$declared_permissions_list); + self::traverse_declared_permissions(self::$declared_permissions, self::$declared_permissions_list); return self::$declared_permissions_list; } @@ -647,8 +623,8 @@ class Permission extends DataObject implements TemplateGlobalProvider { /** * Look up the human-readable title for the permission as defined by Permission::declare_permissions * - * @param $perm Permission code - * @return Label for the given permission, or the permission itself if the label doesn't exist + * @param string $perm Permission code + * @return string Label for the given permission, or the permission itself if the label doesn't exist */ public static function get_label_for_permission($perm) { $list = self::get_declared_permissions_list(); @@ -660,8 +636,8 @@ class Permission extends DataObject implements TemplateGlobalProvider { * Recursively traverse the nested list of declared permissions and create * a linear list. * - * @param aeeay $declared Nested structure of permissions. - * @param $list List of permissions in the structure. The result will be + * @param array $declared Nested structure of permissions. + * @param array $list List of permissions in the structure. The result will be * written to this array. */ protected static function traverse_declared_permissions($declared, &$list) { diff --git a/security/PermissionCheckboxSetField.php b/Security/PermissionCheckboxSetField.php similarity index 93% rename from security/PermissionCheckboxSetField.php rename to Security/PermissionCheckboxSetField.php index 24e6932f0..02bff51a1 100644 --- a/security/PermissionCheckboxSetField.php +++ b/Security/PermissionCheckboxSetField.php @@ -1,10 +1,19 @@ hiddenPermissions = $codes; } /** - * @return Array + * @return array */ public function getHiddenPermissions() { return $this->hiddenPermissions; @@ -81,7 +90,7 @@ class PermissionCheckboxSetField extends FormField { /** * @param array $properties - * @return HTMLText + * @return DBHTMLText */ public function Field($properties = array()) { Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/CheckboxSetField.css'); @@ -96,7 +105,7 @@ class PermissionCheckboxSetField extends FormField { $record = $this->form->getRecord(); if( $record - && (is_a($record, 'Group') || is_a($record, 'PermissionRole')) + && ($record instanceof Group || $record instanceof PermissionRole) && !$records->find('ID', $record->ID) ) { $records->push($record); @@ -117,7 +126,7 @@ class PermissionCheckboxSetField extends FormField { // Special case for Group records (not PermissionRole): // Determine inherited assignments - if(is_a($record, 'Group')) { + if(is_a($record, 'SilverStripe\\Security\\Group')) { // Get all permissions from roles if ($record->Roles()->Count()) { foreach($record->Roles() as $role) { @@ -172,7 +181,7 @@ class PermissionCheckboxSetField extends FormField { $odd = 0; $options = ''; - $globalHidden = (array)Config::inst()->get('Permission', 'hidden_permissions'); + $globalHidden = (array)Config::inst()->get('SilverStripe\\Security\\Permission', 'hidden_permissions'); if($this->source) { $privilegedPermissions = Permission::config()->privileged_permissions; @@ -188,7 +197,7 @@ class PermissionCheckboxSetField extends FormField { $odd = ($odd + 1) % 2; $extraClass = $odd ? 'odd' : 'even'; $extraClass .= ' val' . str_replace(' ', '', $code); - $itemID = $this->id() . '_' . preg_replace('/[^a-zA-Z0-9]+/', '', $code); + $itemID = $this->ID() . '_' . preg_replace('/[^a-zA-Z0-9]+/', '', $code); $checked = $disabled = $inheritMessage = ''; $checked = (isset($uninheritedCodes[$code]) || isset($inheritedCodes[$code])) ? ' checked="checked"' @@ -240,7 +249,7 @@ class PermissionCheckboxSetField extends FormField { } if($this->readonly) { return DBField::create_field('HTMLText', - "