/** * 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; } }