Login method

Purpose

You want to authenticate your guests/staff against a service we haven’t covered yet.

LoginMethodExtension class

To create a custom login method extend the Iacbox\Loginpage\Extension\LoginMethodExtension class.

Class reference
/**
 * Returns unique internal name used to identify LoginMethod (a-z0-9)
 * Override this method to set unique internal name of the login method
 * @return string internal name of login method
 */
public function getName():string {}

/**
 * Returns name which is used in login page editor
 * Override this method to set display name of login method 
 * @return string Name displayed in editor
 */
public function getDisplayName():string {}

/**
 * Returns the priority of extension which defaults to LoginpageCallback::PRIO_DEFAULT = 50.
 * Override this method to return a higher or lower priority for this extension. This influences the order of executed handlers.
 * @return int Priority of Extension (0 = lowest; 100 = highest) - default is 50
 */
public function getPriority():int {}

/**
 * Runs immeadiatly after login method is loaded
 * Override this method to run code immeadiatly after extension is loaded
 * @return void
 */
public function onLoaded() {}

/**
 * Runs during initialization of login method
 * Override this method to run code immeadiatly after extension is loaded
 * @api
 * @param Request $request Request from loginpage
 * @return void
 */
public function onInit(Request $request) {}

/**
 * Returns css class icon used for login method
 * Override this method to set icon used for login method
 * @return string CSS icon class constant from HtmlBuilder
 */
public function getIconCSS():string {}

/**
 * Handles the login and sets new login page state 
 * Override this method to process login attempt for this login method
 * @param Request $request Request from login page
 * @return int Login page state defined in session object
 */
public function processLogin(Request &$request):int {}

/**
 * Returns DOMElement representing the login method for each login page state
 * Override this method to return DOMElement rendered in loginbox for this loginmethod
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param string $parentID ID of loginbox required for some functions
 * @return DOMElement DOMElement representing the login method in current login page state
 */
public function prepareRender(Request &$request, HtmlBuilder $builder, string $parentID):DOMElement {}

/**
 * Returns instance of RenderHelper Class
 * @return RenderHelper Instance of RenderHelper
 */
public function getRenderHelper():RenderHelper {}

/**
 * Check if code is called in login page editor
 * @return bool true if called in login page editor
 */
public function inPreviewMode():bool {}

/**
 * Check if code is called in login page
 * @return bool true if called in login page
 */
public function inProductionMode():bool {}

/**
 * Logs error for debugging
 * @param string $message Message displayed
 * @param Throwable $error Php error object for message and stack trace
 * @return void
 */
public function logError(string $message, Throwable $error = null) {}

/**
 * Logs warning for debugging 
 * @param string $message Message displayed
 * @return void
 */
public function logWarning(string $message) {}

/**
 * Logs info for debugging 
 * @param string $message Message displayed
 * @return void
 */
public function logInfo(string $message) {}

/**
 * Returns config for extension set in login page editor
 * @param Request $request Request from login page
 * @param bool $forceReload force reloading of config 
 * @return array Config hash from extension config or empty hash if no config found
 */
protected function getPageConfig():?array {}

/**
 * Call during onInit() to prevent login page from rendering
 * Override this method to run code immeadiatly after extension is loaded
 * @param string $errorMessage Error message used in login pag exception
 * @return void
 */
public function throwInitializationError(string $errorMessage) {}

/**
 * Check if login method is active
 * @param Request $request Request from login page
 * @return bool true if login method is active
 */
public function isActive(Request $request):bool {}

/**
 * Returns if agreement to Terms of Use is mandatory in webadmin settings
 * @return bool true if mandatory
 */
public function forceTermsOfUse():bool {}

/**
 * Returns if agreement Privacy Policy is mandatory in webadmin settings
 * @return bool true if mandatory
 */
public function forcePrivacyPolicy():bool {}

/**
 * Returns if Terms of Use is activated in webadmin settings
 * @return bool true if Terms Of Use is acitve
 */
public function isTermsOfUseActive():bool {}

/**
 * Returns if Privacy Policy activated in webadmin settings
 * @return bool true if Privacy Policy is active
 */
public function isPrivacyPolicyActive():bool {}

/**
 * Creates root div DOMElement with all required fields to work with login methods
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param DOMElement $form form or DOMElement to append to root div
 * @return DOMElement root div required for login methods
 */
public function createLoginMethodDiv(HTMLBuilder $builder, DOMElement $form):DOMElement {}

/**
 * Creates form DOMElement with all required fields to work for login mehtods
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param bool $ignoreRender set flag to ignore form for onPrepareRender calls
 * @param array $cssClasses Array of additional css classes
 * @return DOMElement form element created
 */
public function createLoginMethodForm(HTMLBuilder $builder, bool $ignoreOnRender = false, array $cssClasses = []):DOMElement {}

/**
 * Returns hash of templates selected by module
 * possible modules: pms, sms, email, ticketrequest, payment, social
 * @param Request $request Request from login page
 * @param string $module Request from login page
 * @param bool $filterVLAN if true only select templates valid for current vlan (default = true)
 * @return array Hash of templates for ticket selection
 */
public function getTemplatesByModule(Request $request, string $module, bool $filterVLAN = true):array {}

/**
 * Returns hash of templates selected with a list of UUIDs
 * @param Request $request Request from login page
 * @param array $uuids List of uuids for templates
 * @param bool $filterVLAN if true only select templates valid for current vlan (default = true)
 * @return array Hash of templates for ticket selection
 */
public function getTemplatesByUUID(Request $request, array $uuids, bool $filterVLAN = true):array {}

/**
 * Returns hash of templates selected with a list of template names
 * @param Request $request Request from login page
 * @param array $uuids List of names for templates
 * @param bool $filterVLAN if true only select templates valid for current vlan (default = true)
 * @return array Hash of templates for ticket selection
 */
public function getTemplatesByName(Request $request, array $names, bool $filterVLAN = true):array {}

/**
 * Filter ticket templates for templates valid with current vlan
 * @param Request $request Request
 * @param array $templates Hash of templates to filter
 * @return array Hash of filtered templates
 */
public function filterTemplatesForVLANRestriction(Request &$request, array $templates):array {}

/**
 * Creates form for ticket selection as in default login methods
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param array $templates Hash of ticket templates as returned by getTemplates functions
 * @return DOMElement form for ticket selection
 */
public function createTicketSelectionForm(Request $request, HtmlBuilder $builder, array $templates):DOMElement {}

/**
 * Check if login method is active and state is PASSWORD_CHANGE_NEEDED
 * @param Request $request Request from login page
 * @return bool true if active and state is PASSWORD_CHANGE_NEEDED 
 */
public function isPasswordChangeNeeded(Request $request):bool {}

/**
 * Creates form for password change as in default login methods
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @return DOMElement form for password change
 */
public function createPasswordChangeForm(Request $request, HtmlBuilder $builder):DOMElement {}

/**
 * Creates form for I already have credentials as in default login methods
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @return DOMElement form for i have credentials
 */
public function createIHaveCredentialsForm(Request $request, HtmlBuilder $builder, string $parentID):DOMElement {}

/**
 * Add div to display login page messages from login page 
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param DOMElement $form Form to which message field is added
 */
public function addLoginpageMessageField(Request $request, HtmlBuilder $builder, DOMElement &$form) {}

/**
 * Add section to display terms of use and privacy notice/checkbox depending on webadmin config
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param DOMElement $form Formto which terms and privacy section is added
 * @param string $parentID ParentID from processLogin function
 * @return void
 */
public function addTermsAndPrivacy(Request $request, HtmlBuilder $builder, DOMElement &$form, string $parentID) {}

/**
 * Add password input field with settings set in loginbox from login page editor
 * Name of post param for password input 'lp-input-password'
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param DOMElement $form Form to which password input is added
 * @return void
 */
public function addPasswordInput(Request $request, HtmlBuilder $builder, DOMElement &$form) {}

/**
 * Add Submit button for login method forms as in default login methods
 * @param Request $request Request from login page
 * @param HtmlBuilder $builder HtmlBuilder from login page
 * @param DOMElement $form Form to which submit button is added
 * @param string $text Text to use for button (default = login as in default login methods)
 * @param string $translationKey Translation key to use for button (default = login as in default login methods)
 * @return void
 */
public function addSubmitLoginMethod(Request $request, HtmlBuilder $builder, DOMElement &$form, string $text = 'logon', string $translationKey = 'logon') {}

/**
 * Process password change for login method with answer from password change form
 * @param Request $request Request
 * @param bool $productionMode production mode of login page
 * @param string $loginMethodName Name of LoginMethod
 */
protected function processPasswordChange(Request &$request, bool $productionMode, string $loginMethodName) {}

/**
 * Send Free login request to LoginService to login client with free login
 * @param Request $request Request
 * @return LoginServiceResponse Response of Login Request
 */
protected function loginFree(Request &$request):LoginServiceResponse {}

/**
 * Send Username password login request to LoginService to login client in ticket with username and password 
 * @param string $username Username for login
 * @param string $password Password for login
 * @param Request $request Request
 * @return LoginServiceResponse Response of Login Request
 */
protected function loginUsernamePassword(string $username, string $password, Request &$request):LoginServiceResponse {}

/**
 * Send password only login request to LoginService to login client with password only ticket
 * @param string $password Password for login
 * @param Request $request Request
 * @return LoginServiceResponse Response of Login Request
 */
protected function loginPasswordOnly(string $password, Request &$request):LoginServiceResponse {}

/**
 * Send SMS with LoginService
 * Requires Sms provider set in webadmin to work
 * @param string $mobileNumber Mobile number of recipient
 * @param string $message Message to send
 * @param string $userid UserId of recipient
 * @param Request $request Request
 * @return LoginServiceResponse Response of Login Request
 */
protected function sendSms(string $mobileNumber, string $message, string $userid, Request &$request):LoginServiceResponse {}

/**
 * Handle LoginServiceResponse if needPasswordChange() is true
 * @param Request $request Request from login page
 * @param LoginServiceResponse $response Response from login
 * @return int login page state to return for processLogin
 */
public function proceedToPasswordChange(Request $request, LoginServiceResponse $response):int {}

/**
 * Add error from LoginServiceResponse to login page messages if hadError() is true
 * @param Request $request Request from login page
 * @param LoginServiceResponse $response Response from login
 * @return void
 */
public function handleResponseError(Request $request, LoginServiceResponse $response) {}

/**
 * Returns error message from LoginServiceResponse
 * @param Request $request Request from login page
 * @param LoginServiceResponse $response Response from login
 * @return string Error message from LoginServiceresponse or '' if no error
 */
public function getResponseErrorMessage(Request $request, LoginServiceResponse $response):string {}

/**
 * Add Error Message to Request
 * @param Request $request Request to which Error message is added
 * @param string $text Error message
 * @param bool $translate If error message should be translated (default: true)
 * @param array $errDetails additional details of error
 */
public function addErrorMessage(Request &$request, string $text, bool $translate = true, array $errDetails = []) {}

/**
 * Add Success Message to Request
 * @param Request $request Request to which Success message is added
 * @param string $text Success message
 * @param bool $translate If success message should be translated (default: true)
 */
public function addSuccessMessage(Request &$request, string $text, bool $translate = true) {}

/**
 * Add Additional Line to message if message is set
 * @param Request $request Request to which line is added to message
 * @param string $text text of additional line
 * @param bool $translate If additional line should be translated (default: true)
 */
public function addInfoToMessage(Request &$request, string $text, bool $translate = true): bool {}

/**
 * Do not overwrite following methods!
 * Required for correct working of extensions in login page 
 */
public function __construct(Logger $log, LoginServiceConnector $loginSrv, Environment $environment, Cache $cache, Config $config) {}

public function init(Router $router) {}

public function setName(string $name) {}

public function setDBConfig(Config $config) {}

public function setConfig(Config $config) {}

public function getConfig(bool $forceReload = false):Config {}

public function setMaskPassword(bool $maskPassword) {}

public function translate(string $text, ?string $fallback = null):string {}

public function forceTermsOfUse():bool {}

public function forcePrivacyPolicy():bool {}

public function isTermsOfUseActive():bool {}

public function isPrivacyPolicyActive():bool {}

protected function buildPostURL(string $loginMethodName, string $pageID = 'page-0'):string {}

public function addErrorMessage(Request &$request, string $text, bool $translate = true, array $errDetails = []) {}

public function addSuccessMessage(Request &$request, string $text, bool $translate = true) {}

public function addInfoToMessage(Request &$request, string $text, bool $translate = true): bool {}

public function getTemplateConfig(string $module = '', array $uuidList = null, array $nameList = null):array {}

Name of login method

Each login method needs an unique lowercase name to be correctly identified in the login page logic. In addition a display name can be assigned to a login method used for title in loginbox tab and editor

Example

// unique identifier for loginmethod - use only alphanumeric chars [a-z0-9]
public function getName():string {
	return 'examplelogin';
}

// name displayed in login page editor
public function getDisplayName():string {
	return 'Example login';
}

Render of login method

The default render state for login methods is AUTH_NEEDED. The current state of the login page is only valid for the active login method, which can be checked with the function isActive().

Example

// return DOM to render login method in login page with correct state
public function prepareRender(Request &$request, HtmlBuilder $builder, string $parentID):DOMElement {
	// check for PASSWORD_CHANGE_NEEDED (some logins can result in this state if activated in webadmin)
	if ($this->isActive() && $request->getSession()->getState() == Session::PASSWORD_CHANGE_NEEDED) {
		// create and return default password change form
		$formForPasswordChange = $this->createPasswordChangeForm($request, $builder);
		return $this->createLoginMethodDiv($builder, $formForState);
	}
	// render login Method in state AUTH_NEEDED
	// get RenderHelper 
	$renderHelper = $this->getRenderHelper();
	// create form for login method
	$form = $this->createLoginMethodForm($builder);
	// adds div to display login page messages and warnings
	$this->addLoginpageMessageField($request, $builder, $form);
	// add fields required for login method
	// add fields for login method
	// ...

	// add terms and privacy as defined in webadmin
	$this->addTermsAndPrivacy($request, $builder, $form, $parentID);
	// add submit button for login method
	$this->addSubmitLoginMethod($request, $builder, $form);
	// return div for login method with form added
	return $this->createLoginMethodDiv($builder, $form);
}

Process login method

During processLogin validate user input and perform the authentication. If validation and authentication has been successful use one of the provided login methods to try to login the user via this backend. After a login attempt handle possible errors from LoginServiceResponse. If no errors occurred and the user is taken online call addResponseToSessionAfterLogin for correct handling in login page logic.

Example

// process requests for this login method
public function processLogin(Request &$request):int {
	// if already online do nothing
	if ($request->getSession()->getState() == Session::ONLINE) {
		return Session::ONLINE;
	// if password change is needed process default password change form
	} else if ($request->getSession()->getState() == Session::PASSWORD_CHANGE_NEEDED) {
		return $this->processPasswordChange($request, $productionMode, $this->getName());
	// else if AUTH_NEEDED
	} else if ($request->getSession()->getState() == Session::AUTH_NEEDED) {
		// check Terms and Privacy Policy
		$termsAndPolicyAccepted = $this->areTermsAndPrivacyAccepted($request);
		if (! $termsAndPolicyAccepted) {
			return Session::AUTH_NEEDED;
		}
		// validate user input and perform additional authentications
		// ...
		if (! $inputCorrect) {
			$this->addErrorMessage($request, 'invalid-or-missing-data');
			return Session::AUTH_NEEDED;
		}
		// set state to AUTH_PENDING
		$request->getSession()->setState(Session::AUTH_EXT_PENDING);
		// get response from backend using on of the login options provided
		$response = $this->loginUsernamePassword($username, $password, $request);
		// check if backend reported password change needed 
		if ($response->needPasswordChange()) {
			return $this->proceedToPasswordChange($request, $response);
		// else if response had an error handle error and return to AUTH_NEEDED
		} else if ($response->hadError()) {
			$this->handleResponseError($request, $response);
			$request->getSession()->setState(Session::AUTH_NEEDED);
			return Session::AUTH_NEEDED;
		}
		// if no error add response data to session and set state to online
		$this->addResponseToSessionAfterLogin($request, $response);
		$request->getSession()->setState(Session::ONLINE);
		return Session::ONLINE;
	// if login method entered with unhandled state
	} else {
		$this->addErrorMessage($request, 'error-wrong-state');
		$request->getSession()->setState(Session::AUTH_NEEDED);
		return Session::AUTH_NEEDED;
	}
	return $request->getSession()->getState();
}

Flowchart of login page states

image