/** * Tries to logon to the FTP server with given id and password * * @access public * * @param string $source Authentication source to be used * @param string $external_uid The ID entered * @param string $external_passwd The password of the user * * @return boolean True if the authentication was a success, false * otherwise */ public function Authenticate($source, $external_uid, $external_passwd) { $enc = ExternalAuthenticator::getAuthEnc($source); $port = ExternalAuthenticator::getAuthPort($source); if (is_null($port)) { $port = self::$port; } ExternalAuthenticator::AuthLog($external_uid . '.ftp - Connecting to ' . ExternalAuthenticator::getAuthServer($source) . ' port ' . $port); if ($enc == 'ssl') { ExternalAuthenticator::AuthLog($external_uid . '.ftp - Connection type is SSL'); $conn = @ftp_ssl_connect(ExternalAuthenticator::getAuthServer($source), $port); } else { $conn = @ftp_connect(ExternalAuthenticator::getAuthServer($source), $port); } if (!$conn) { ExternalAuthenticator::AuthLog($external_uid . '.ftp - Connection to server failed'); ExternalAuthenticator::setAuthMessage(_t('FTP_Authenticator.NoConnect', 'Could not connect to FTP server')); return false; } else { ExternalAuthenticator::AuthLog($external_uid . '.ftp - Connection to server succeeded'); } if (!@ftp_login($conn, $external_uid, $external_passwd)) { ExternalAuthenticator::AuthLog($external_uid . '.ftp - User credentials failed at ftp server'); ftp_close($conn); ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } else { ExternalAuthenticator::AuthLog($external_uid . '.ftp - ftp server validated credentials'); ftp_close($conn); return true; } }
/** * Tries to logon using the credentials in the SilverStripe database * * @access public * * @param string $source Authentication source to be used * @param string $external_uid The ID entered * @param string $external_passwd The password of the user * * @return boolean True if the authentication was a success, false * otherwise */ public function Authenticate($RAW_source, $RAW_external_uid, $RAW_external_passwd) { $SQL_identity = Convert::raw2sql($RAW_external_uid); // Default login (see Security::setDefaultAdmin()) if (Security::check_default_admin($RAW_external_uid, $RAW_external_passwd)) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Logging on with an Administrator account'); $member = Security::findAnAdministrator(); } else { $SQL_source = Convert::raw2sql($RAW_source); ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Searching for user with source ' . $SQL_source . ' in database'); $member = DataObject::get_one("Member", "\"Member\".\"External_UserID\" = '{$SQL_identity}'" . " AND \"Member\".\"External_SourceID\" = '{$SQL_source}'" . " AND \"Password\" IS NOT NULL"); if ($member) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - User was found in database'); if ($member->checkPassword($RAW_external_passwd) == false) { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Password authentication failed'); $member = null; } else { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - Password authentication succeeded'); } } else { ExternalAuthenticator::AuthLog($RAW_external_uid . '.sstripe - User was NOT found in database'); } } if ($member) { return true; } else { ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } }
/** * Change the member dialog in the CMS * * This method updates the form in the member dialog to make it possible * to edit the new database fields. */ function updateCMSFields(FieldList $fields) { // let make sure, this runs only once (because member and dataobject both extend updateCMSFields // making it run twice!) $cp = $fields->fieldByName('Root'); if ($cp && $cp->fieldByName('ExternalAuthentication')) { return; } $sources = ExternalAuthenticator::getIDandNames(); $sources = array_merge(array("" => "-"), $sources); $fields->findOrMakeTab('Root.ExternalAuthentication', _t('ExternalAuthenticator.Title')); $fields->addFieldToTab('Root.ExternalAuthentication', new HeaderField('External_Header', _t('ExternalAuthenticator.ModFormHead', 'ID for external authentication source'))); $fields->addFieldToTab('Root.ExternalAuthentication', new LiteralField('ExternalDescription', _t('ExternalAuthenticator.EnterUser', 'Enter the user id and authentication source for this user'))); $fields->addFieldToTab('Root.ExternalAuthentication', new DropdownField('External_SourceID', _t('ExternalAuthenticator.Sources'), $sources)); $fields->addFieldToTab('Root.ExternalAuthentication', new TextField('External_Anchor', _t('ExternalAuthenticator.EnterNewId', 'ID to be used with this source'))); }
/** * Tries to logon to the IMAP server with given id and password * * @access public * * @param string $source Authentication source to be used * @param string $external_uid The ID entered * @param string $external_passwd The password of the user * * @return boolean True if the authentication was a success, false * otherwise */ public function Authenticate($source, $external_uid, $external_passwd) { $servicetype = ExternalAuthenticator::getOption($source, 'protocol'); if (is_null($servicetype) || !in_array(strtolower($servicetype), array('imap', 'pop3'))) { ExternalAuthenticator::setAuthMessage(_t('IMAP_Authenticator.Protocol', 'Protocol is not set to a valid type')); return false; } $enc = ExternalAuthenticator::getAuthEnc($source); $port = ExternalAuthenticator::getAuthPort($source); if (is_null($port)) { if (is_null($enc)) { $port = self::$portlist["{$servicetype}"]['default']; } else { $port = self::$portlist["{$servicetype}"]["{$enc}"]; } } $connectstring = '{' . ExternalAuthenticator::getAuthServer($source); $connectstring .= ':' . $port; $connectstring .= '/' . $servicetype; if (!is_null($enc)) { $connectstring .= '/' . $enc; $validate = ExternalAuthenticator::getOption($source, 'certnovalidate'); if (!is_null($validate) || $validate) { $connectstring .= '/novalidate-cert'; } } else { $connectstring .= '/notls'; } $connectstring .= '}'; ExternalAuthenticator::AuthLog($external_uid . '.imap - Connect string to server is ' . $connectstring); ExternalAuthenticator::AuthLog($external_uid . '.imap - If you get a blank screen and the process end here, check php_imap module'); $mbox = @imap_open($connectstring, $external_uid, $external_passwd); if (!$mbox) { ExternalAuthenticator::AuthLog($external_uid . '.imap - ' . imap_last_error()); ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } else { ExternalAuthenticator::AuthLog($external_uid . '.imap - imap_open returned mailbox handle'); @imap_close($mbox); return true; } }
function setUp() { // This test assumes that MemberAuthenticator is present and the default $this->priorAuthenticators = Authenticator::get_authenticators(); $this->priorDefaultAuthenticator = Authenticator::get_default_authenticator(); //Authenticator::register('MemberAuthenticator'); Authenticator::register_authenticator('ExternalAuthenticator'); Authenticator::set_default_authenticator('ExternalAuthenticator'); //Create the sources in this order. Switching them around would mean that //all tests use the fake driver because this always succeeds and auto create //is on ExternalAuthenticator::createSource('sstripe_unittest', 'SSTRIPE', 'SilverStripe'); ExternalAuthenticator::createSource('fake_unittest', 'FAKE', 'Fake Source'); ExternalAuthenticator::setAuthSequential(true); ExternalAuthenticator::setAuthSSLock('sstripe_unittest', true); ExternalAuthenticator::setAuthSSLock('fake_unittest', false); ExternalAuthenticator::setAutoAdd('fake_unittest', 'mygroup'); ExternalAuthenticator::setDefaultDomain('fake_unittest', 'silverstripe.com'); ExternalAuthenticator::setAuthDebug(false); ExternalAuthenticator::setAuditLogFile(false); ExternalAuthenticator::setAuditLogSStripe(true); parent::setUp(); }
/** * Tries to logon to the LDAP server with given id and password * * @access public * * @param string $source The Authentication source to be used * @param string $external_anchor The ID entered * @param string $external_passwd The password of the user * * @return mixed Account details if succesful , false if not */ public function Authenticate($source, $external_anchor, $external_passwd) { // A password should have some lenght. An empty password will result // in a succesfull anonymous bind. A password should not be all spaces if (strlen(trim($external_passwd)) == 0) { ExternalAuthenticator::setAuthMessage(_t('LDAP_Authenticator.NoPasswd', 'Please enter a password')); return false; } // Do we support password expiration? $expire = ExternalAuthenticator::getOption($source, 'passwd_expiration'); $result = self::Connect($source, $external_anchor); if (is_string($result)) { ExternalAuthenticator::setAuthMessage($result); return false; } $dn = self::findDN($source, ExternalAuthenticator::getOption($source, 'attribute'), $external_anchor); if (is_bool($dn)) { @ldap_close(self::$ds); ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } // Restore the default error handler. We dont want a red bordered // screen on error, but a civilized message to the user restore_error_handler(); $success = false; //Initialize the result of the authentication ExternalAuthenticator::AuthLog($external_anchor . '.ldap - Binding to LDAP as ' . $dn); $bind = @ldap_bind(self::$ds, $dn, $external_passwd); if ($bind != false) { ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP accepted password for ' . $dn); $accountdetails = self::lookupDetails($source, $dn, $external_anchor); if (!is_null($expire) && $expire) { ExternalAuthenticator::AuthLog($external_anchor . '.ldap - Check if password has expired'); // Reset the SilverStripe error handler Debug::loadErrorHandlers(); // Do some calculations on the attributes to convert them // to the interval [now]-[expires at] if ($accountdetails['shadowmax']['value'] && $accountdetails['shadowlastchange']['value'] && $accountdetails['shadowwarning']['value']) { $today = floor(time() / 86400); $warnday = $accountdetails['shadowlastchange']['value'] + $accountdetails['shadowmax']['value'] - $accountdetails['shadowwarning']['value']; $toexpire = $accountdetails['shadowlastchange']['value'] + $accountdetails['shadowmax']['value'] - $today; ExternalAuthenticator::AuthLog($external_anchor . '.ldap - ' . $toexpire . ' before password expires ' . $towarn . ' days before warning'); // Out of luck. His password has expired. if ($toexpire < 0) { ExternalAuthenticator::setAuthMessage(_t('LDAP_Authenticator.Expired', 'Your password has expired')); ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP Authentication FAILED due to expired password'); } else { ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP Authentication success'); $success = array('firstname' => $accountdetails['firstname']['value'], 'surname' => $accountdetails['surname']['value'], 'email' => $accountdetails['email']['value'], 'group' => $accountdetails['group']['value']); // Lets be civilized and warn the user that he should // change his password soon if ($today >= $warnday) { ExternalAuthenticator::setAuthMessage(sprintf(_t('LDAP_Authenticator.WillExpire', 'Your password expires in %d days'), $toexpire)); } } } else { ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP password expiry enabled, but attributes not set; IGNORING'); ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP Authentication success'); $success = array('firstname' => $accountdetails['firstname']['value'], 'surname' => $accountdetails['surname']['value'], 'email' => $accountdetails['email']['value'], 'group' => $accountdetails['group']['value']); } } else { ExternalAuthenticator::AuthLog($external_anchor . '.ldap - Password expiry not enabled'); // Reset the SilverStripe error handler Debug::loadErrorHandlers(); ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP Authentication success'); $success = array('firstname' => $accountdetails['firstname']['value'], 'surname' => $accountdetails['surname']['value'], 'email' => $accountdetails['email']['value'], 'group' => $accountdetails['group']['value']); } } else { // Reset the SilverStripe error handler Debug::loadErrorHandlers(); ExternalAuthenticator::AuthLog($external_anchor . '.ldap - LDAP authentication for ' . $dn . ' failed'); ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); $success = false; } @ldap_close(self::$ds); return $success; }
/** * Try to authenticate the user * * @param array Submitted data * @return Member Returns the member object on successful authentication * or NULL on failure. */ public function performLogin($data) { if ($member = ExternalAuthenticator::authenticate($data, $this)) { $member->LogIn(isset($data['Remember'])); return $member; } else { return null; } }
/** * Method to authenticate an user * * @param $RAW_data Raw data to authenticate the user * @param Form $form Optional: If passed, better error messages can be * produced by using * {@link Form::sessionMessage()} * @return bool Returns FALSE if authentication fails, otherwise the * member object */ public static function authenticate($RAW_data, Form $form = null) { $RAW_external_anchor = trim($RAW_data['External_Anchor']); $RAW_external_mailaddr = trim($RAW_data['External_MailAddr']); $RAW_external_source = trim($RAW_data['External_SourceID']); $RAW_external_passwd = $RAW_data['Password']; $userexists = false; //Does the user exist within SilverStripe? $userindbs = false; //Does the user already exist in the SStripe dbs? $authsuccess = false; //Initialization of variable //Set authentication message for failed authentication //Could be used by the individual drivers self::$authmessage = _t('ExternalAuthenticator.Failed', 'Authentication failed'); self::AuthLog('Starting process for with alleged Anchor ' . $RAW_external_anchor . ' and alleged mail ' . $RAW_external_mailaddr . ' at ' . self::$timestamp); if ($memberquery = self::getHandleToUse($RAW_external_anchor, $RAW_external_mailaddr, $RAW_external_source, $form)) { if ($member = DataObject::get_one('Member', $memberquery)) { $Log_ID = $member->Email; // Before we continue we must check if the source is valid if (!self::validSource($member->External_SourceID, $Log_ID, $member)) { self::failmessage($form, $member, $Log_ID, $RAW_external_source); return false; } $userexists = true; $userindbs = true; self::AuthLog($Log_ID . ' - User with source ' . $member->External_SourceID . ' found in database'); if (!self::getUseAnchor()) { $RAW_external_source = stripslashes($member->External_SourceID); $RAW_external_anchor = stripslashes($member->External_Anchor); } //Check if the user was behaving nicely if (self::accountLockedOut($member, $Log_ID)) { self::failmessage($form, $member, $Log_ID, $RAW_external_source); return false; } } else { $Log_ID = 'unknown'; self::Authlog($Log_ID . ' - User with source NOT found in database'); } } else { // Authentication form was not filled out properly return false; } if (!$userexists && self::getUseAnchor()) { if (self::validSource($RAW_external_source, $Log_ID)) { if (self::getAutoAdd($RAW_external_source)) { $userexists = true; } else { self::Authlog($Log_ID . ' - AutoAdd for source ' . $RAW_external_source . ' not enabled, aborting'); self::failmessage($form, $member, $Log_ID, $RAW_external_source); return false; } } else { self::failmessage($form, $member, $Log_ID, $RAW_external_source); self::Authlog($Log_ID . ' - Illegal source ' . $RAW_external_source . ' or client not in valid IP range; aborting'); return false; } } // Try to find our anchor, since we have none if (!$userexists && !self::getUseAnchor()) { foreach (self::getSources() as $source) { if (self::getAutoAdd($source)) { $auth_type = strtoupper(self::getAuthType($source)); self::AuthLog($Log_ID . ' - loading driver ' . $auth_type); //If we don't have a user yet and autoadd is on; try to find the anchor if ($memberdata = self::locateAnchor($source, $RAW_external_mailaddr, $Log_ID)) { extract($memberdata); $userexists = true; break; } } } } else { // Load the correct driver if (!self::validSource($RAW_external_source, $Log_ID)) { $form->sessionMessage(_t('ExternalAuthenticator.Failed'), 'bad'); self::Authlog($Log_ID . ' - Illegal source ' . $RAW_external_source . ' or client not in valid IP range; aborting'); self::failmessage($form, $member, $Log_ID, $RAW_external_source); return false; } $auth_type = strtoupper(self::getAuthType($RAW_external_source)); self::AuthLog($Log_ID . ' - loading driver ' . $auth_type); } if ($userexists) { $myauthenticator = $auth_type . '_Authenticator'; $myauthenticator = new $myauthenticator(); self::AuthLog($Log_ID . ' - executing authentication driver'); $RAW_result = $myauthenticator->Authenticate($RAW_external_source, $RAW_external_anchor, $RAW_external_passwd); if ($RAW_result) { $authsuccess = true; self::AuthLog($Log_ID . ' - authentication success'); } else { self::AuthLog($Log_ID . ' - authentication driver ' . $auth_type . ' failed'); if ($member && self::getAuthSSLock($RAW_external_source)) { self::AuthLog($Log_ID . ' - Registering failed login'); $member->registerFailedLogin(); } } } // Check if we need to do something with the groups if ($authsuccess) { // We're an array, so we need to do auto-mapping // first determine which group we should be a member of $usergroup = self::getMyGroup($RAW_external_source, $RAW_result['group']); if (!$userindbs && !is_bool($usergroup)) { $SQL_memberdata = self::createMemberArray($RAW_result, $RAW_external_anchor, $RAW_external_source, self::getDefaultDomain($RAW_external_source)); // First we check if the user's e-mail address has changed // we do this by checking if the anchor and source are already in the dbs // we do this only if the user used his mail address to authenticate // If the user does not exist we create a new member object if (!self::getUseAnchor()) { // First we check if the user's e-mail address has changed // we do this by checking if the anchor and source are already in the dbs // we do this only if the user used his mail address to authenticate // If the user does not exist we create a new member object if (!($member = DataObject::get_one('Member', '"Member"."External_Anchor" = \'' . $SQL_memberdata['External_Anchor'] . '\' AND "Member"."External_SourceID" = \'' . $SQL_memberdata['External_SourceID'] . '\''))) { $member = new Member(); self::AuthLog($Log_ID . ' - Anchor does not exist in database.'); } else { self::AuthLog($Log_ID . ' - Anchor already present in the database but mail address is unknown. Changing mail address for this anchor'); $userindbs = true; self::AuditLog($member, $Log_ID, 'modify', 'account exists', true, $RAW_external_source); } } else { // Now we check if the users e-mail address already exists. He // did not authenticate himself with the mail address and we // assume that if authentication was successful, he is owner // of the address. This supports moving users from one source // to another if (!($member = DataObject::get_one('Member', '"Email" = \'' . $SQL_memberdata['Email'] . '\''))) { $member = new Member(); self::AuthLog($Log_ID . ' - Mail address does not exist in the database'); } else { self::Authlog($Log_ID . ' - Mail address already present in the database, modifying existing account'); $userindbs = true; self::AuditLog($member, $Log_ID, 'modify', 'account exists', true, $RAW_external_source); } } // But before we write ourselves to the database we must check if // the group we are subscribing to exists if (!is_bool($usergroup)) { $member->update($SQL_memberdata); if (!$userindbs) { $member->ID = null; } self::AuthLog($Log_ID . ' - start adding or modifying user'); $member->write(); self::AuthLog($Log_ID . ' - finished adding user to database'); if (!$userindbs) { self::AuthLog($Log_ID . ' - start setting group membership to group ' . $usergroup->Title); $member->Groups()->add($usergroup->ID); self::AuthLog($Log_ID . ' - finished setting group membership'); } self::AuditLog($member, $Log_ID, 'creation', NULL, true, $RAW_external_source); } else { self::AuthLog($Log_ID . ' - The group to add the user to did not exist'); $authsuccess = false; } } if ($userindbs && !is_bool($usergroup)) { self::AuthLog($Log_ID . ' - Group membership will be set to ID ' . $usergroup->ID . ' name ' . $usergroup->Title); // User exists. We should check current group against group from config $memberships = $member->Groups()->getIdList(); if (array_key_exists($usergroup->ID, $memberships)) { self::AuthLog($Log_ID . ' - User is already a member of ' . $usergroup->Title); } else { foreach ($memberships as $membership) { self::AuthLog($Log_ID . ' - Erasing membership of group ' . $membership); $member->Groups()->remove(self::groupObj($membership)); self::AuthLog($Log_ID . ' - Done erasing membership of group ' . $membership); } self::AuthLog($Log_ID . ' - setting membership of ' . $usergroup->Title); self::Auditlog($member, $Log_ID, 'modify', 'current group membership does not match configuration', true, $RAW_external_source); $member->Groups()->add($usergroup->ID); self::AuthLog($Log_ID . ' - Done setting membership of ' . $usergroup->Title); } } } self::AuthLog('Process for user ' . $Log_ID . ' ended'); if ($authsuccess) { Session::clear('BackURL'); self::$authmessage = ''; // Set the security message here. Else it will be shown on logout Session::set('Security.Message.message', self::$authmessage); Session::set('Security.Message.type', 'good'); self::AuditLog($member, $Log_ID, 'logon', NULL, true, $RAW_external_source); return $member; } else { self::failmessage($form, $member, $Log_ID, $RAW_external_source); return false; } }
/** * Tries to logon to the HTTP server with given id and password * * @access public * * @param string $source Authentication source to be used * @param string $external_uid The ID entered * @param string $external_passwd The password of the user * * @return boolean True if the authentication was a success, false * otherwise */ public function Authenticate($source, $external_uid, $external_passwd) { require_once 'HTTP/Request.php'; // Set some default HTTP request options $request_options['method'] = 'GET'; $request_options['timeout'] = 5; $request_options['allowRedirects'] = true; $enc = ExternalAuthenticator::getAuthEnc($source); $port = ExternalAuthenticator::getAuthPort($source); $folder = ExternalAuthenticator::getOption($source, 'folder'); $proxy = ExternalAuthenticator::getOption($source, 'proxy'); $proxy_port = ExternalAuthenticator::getOption($source, 'proxy_port'); $proxy_user = ExternalAuthenticator::getOption($source, 'proxy_user'); $proxy_pass = ExternalAuthenticator::getOption($source, 'proxy_pass'); if (!is_null($proxy) && !is_null($proxy_port)) { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy is set to ' . $proxy . ':' . $proxy_port); $request_options['proxy_host'] = $proxy; $request_options['proxy_port'] = $proxy_port; } else { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy is not set'); } if (!is_null($proxy_user)) { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy user is set to ' . $proxy_user); $request_options['proxy_user'] = $proxy_user; if (!is_null($proxy_pass)) { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy password is set'); $request_options['proxy_pass'] = $proxy_pass; } else { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy password is NOT set'); } } else { ExternalAuthenticator::AuthLog($external_uid . '.http - Proxy user is NOT set'); } if ($enc == 'ssl') { $url = 'https://'; } else { $url = 'http://'; } $url .= ExternalAuthenticator::getAuthServer($source); if (!is_null($port)) { $url .= ':' . $port; } if (!is_null($folder)) { $url .= $folder; } ExternalAuthenticator::AuthLog($external_uid . '.http - Authentication URL is set to ' . $url); $request = new HTTP_Request($url, $request_options); $request->setBasicAuth($external_uid, $external_passwd); ExternalAuthenticator::AuthLog($external_uid . '.http - Sending authentication request'); $request->sendRequest(); // HTTP code 200 means everything is OK if ($request->getResponseCode() == 200) { ExternalAuthenticator::AuthLog($external_uid . '.http - Remote server returned code 200'); return true; } else { ExternalAuthenticator::AuthLog($external_uid . '.http - Authentication failed with HTTP code ' . $request->getResponseCode()); ExternalAuthenticator::setAuthMessage(_t('ExternalAuthenticator.Failed')); return false; } }
/** * Tries to find the anchor for a given mail address and source * * @access public * * @param string $source The Authentication source to be used * @param string $mailaddr The mail address entered * * @return mixed Anchor as string or false if not found **/ public function getAnchor($source, $mailaddr) { ExternalAuthenticator::AuthLog($mailaddr . '.fake - Anchor lookup not supported by source ' . $source); return false; }