Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
Ashutosh_Rai1
Associate
Associate
857

In this blog , we will go through step by step process to modify SAP Fiori Launchpad logon page (specifically adding CAPTCHA feature in SAP Private Cloud/on-prem System).

(1)   Setup SAP backend system in ADT.  You can refer this learning journey for the same Create an ABAP Project in ABAP Development Tools (ADT) | SAP Tutorials

(2)  Once setup is completed create a new development package in ADT , for that follow below steps:

  (a) Right click on Favorite Packages -> New -> ABAP Package

        Ashutosh_Rai1_0-1759677217972.png

  (b) Enter values as highlighted below in screenshots : 

       Ashutosh_Rai1_2-1759677844383.png

       Ashutosh_Rai1_3-1759677938301.png

       Ashutosh_Rai1_5-1759678270579.png

(3) We will now create a custom BSP application so that we can try-out our custom logon screen without impacting end-users. For this follow below steps :

   (a) Right click on ZFIORI_CUSTOM_LOGON -> New -> Other ABAP Repository Object

        Ashutosh_Rai1_6-1759678638968.png

    (b) Search for "BSP" keyword and select "BSP Application

       Ashutosh_Rai1_8-1759678969335.png

   (c) Give the BSP object name , this will be used for testing 

      Ashutosh_Rai1_9-1759679081620.png

  (d) Activate the newly created BSP page , by clicking on Activate button

     Ashutosh_Rai1_10-1759679396638.png

   (e) Go to "sicf" tcode to test service 

     Ashutosh_Rai1_11-1759679608722.png                  Ashutosh_Rai1_12-1759679668295.png

 

  (f) You might get Authorization error like below , please note that as of now we just want to test if the object is active or not 

        Ashutosh_Rai1_14-1759681153769.png

(4) Now we will create a custom class in order to redefine standard logon class. In order to procced , follow below steps :

 (a) Create a new class inside the same package

     Ashutosh_Rai1_15-1759684262826.png

    (b) Give below details and click Next 

    Ashutosh_Rai1_16-1759684614081.png

   (c) Give TR details and click on Finish

    Ashutosh_Rai1_18-1759684853540.png

(5) Copy this code snippet and paste it in our custom ZCL_CUSTOM_FIORI_LOGIN class : 

CLASS zcl_custom_fiori_login DEFINITION
  PUBLIC
  INHERITING FROM /ui2/cl_fiori3_login
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.


CLASS zcl_custom_fiori_login IMPLEMENTATION.
  
ENDCLASS.

(6) We will now create custom JavaScript file which will be called during logon page load by following below steps :

   (a) Create a file "zlogin_ext.js" and paste this code snippet :

/*!
 * SAP Fiori login - add CAPTCHA along with Refresh button for the same
*/

document.addEventListener( 'DOMContentLoaded', (event) => {
  const w = "white";
   if (document.getElementById("LOGIN_LINK") !== null) {
   document.getElementById("CHANGE_PASSWORD_LINK").style.color = w;
   
    // Function to get the CAPTCHA name
  function getCaptchaValue() {

	var alpha = new Array("A", "B", "C", "D", "E", "F", "G","H", "I", "J", 
        	              "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
                	      "U", "V", "W","X", "Y", "Z", "a", "b", "c", "d", 
        	              "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
       		              "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
		     "y", "z");
	var i;
	for (i = 0; i < 6; i++) {
		var a = alpha[Math.floor(Math.random() * alpha.length)];
        	var b = Math.ceil(Math.random() * 10) + "";
		var c = alpha[Math.floor(Math.random() * alpha.length)];
		var d = alpha[Math.floor(Math.random() * alpha.length)];
		var e = Math.ceil(Math.random() * 10) + "";
		var f = alpha[Math.floor(Math.random() * alpha.length)];
		var g = alpha[Math.floor(Math.random() * alpha.length)];
	}
	var code = a + " " + b + " " + " " + c + " " + d + " " + e + " " + f + " " + g;
	var bCode = code.split(" ").join("");
  	return bCode;


  }

  const captchaLabel = document.createElement("text");
  captchaLabel.textContent = getCaptchaValue();
  captchaLabel.setAttribute("for", "captchaField");
  captchaLabel.style.fontSize = '24px';


  const captchaInput = document.createElement("input");
  captchaInput.setAttribute("type", "text");
  captchaInput.setAttribute("id", "captchaField");
  captchaInput.setAttribute("name", "CAPTCHA"); 
  captchaInput.setAttribute("required", "true"); 
  captchaInput.setAttribute("placeholder", "Please enter Captcha");
  captchaInput.style.width = "280px";
  captchaInput.style.fontSize = '15px';
  captchaInput.style.height = "35px";
  
  

  const passwordBlock = document.getElementById("PASSWORD_BLOCK");

  const captchaBlock = document.createElement("div");
  captchaBlock.id = "CAPTCHA_BLOCK"; 
  
  const captchaLabelWrapper = document.createElement("div");
  captchaLabelWrapper.style.display = "flex";
  captchaLabelWrapper.style.alignItems = "center"; 
  captchaLabelWrapper.appendChild(captchaLabel);
  captchaLabelWrapper.style.marginBottom = "20px"; 
  captchaLabelWrapper.style.marginTop = "20px"; 
   

  const refreshButton = document.createElement("button");
  refreshButton.innerHTML = "&#x21BB;"; // Unicode refresh icon (clockwise arrows)
  refreshButton.style.marginLeft = "50px"; 
  refreshButton.style.padding = "5px 10px";
  refreshButton.style.cursor = "pointer";
  refreshButton.style.backgroundColor = "#5CACEE"; 
  refreshButton.style.color = "white";
  refreshButton.style.border = "none";
  refreshButton.style.borderRadius = "3px";
  refreshButton.style.fontSize = "30px"; 
  captchaLabelWrapper.appendChild(refreshButton);

  captchaBlock.appendChild(captchaLabelWrapper);
  captchaBlock.appendChild(captchaInput);
  passwordBlock.insertAdjacentElement('afterend', captchaBlock); 
  
  const messageDiv = document.createElement("div");
  messageDiv.id = "captchaMessage";
  messageDiv.style.color = "red"; 
  messageDiv.style.marginTop = "5px"; 
  captchaBlock.appendChild(messageDiv); 

  let displayedCaptcha = captchaLabel.textContent; 
  const userEnteredCaptcha = captchaInput.value;
 
  
  const loginButton = document.getElementById("LOGIN_LINK"); 
  loginButton.disabled = true; 
  
  function updateCaptcha() {
    captchaLabel.textContent = getCaptchaValue();
    displayedCaptcha = captchaLabel.textContent;
    captchaInput.value = ""; 
    loginButton.disabled = true; 
    messageDiv.textContent = "";
  }
  
  refreshButton.addEventListener('click', () => {
    updateCaptcha();
  });
  
  captchaInput.addEventListener('input', () => { 
    
  	if (document.getElementById("captchaField").value === displayedCaptcha) {
        	loginButton.disabled = false; 
        	messageDiv.textContent = ""; 
    	} else {
        	loginButton.disabled = true;  
        	messageDiv.textContent = "Please enter correct Captcha and click on Logon again"; 
    	}
    
  });
 
   
  //Event listener to enable or disable Standard Login button based on CAPTCHA validation
  loginButton.addEventListener('click', (e) => { 
        
   
  	if (displayedCaptcha === document.getElementById("captchaField").value) {
  		loginButton.closest('form').submit(); 
                messageDiv.textContent = "";
                
   	} else {
                e.preventDefault();
                messageDiv.textContent = "Please enter correct Captcha"; 
                                
  	}
  })

  }

})

     (b) The above JavaScript code snippet will basically create a "CAPTCHA" label and input field. Catpcha text will be displayed in the label. Along with that there will be additional "Refresh" button to get new Captcha. It also display error message 

    (c) Goto "se80" tcode and import this "zlogin_ext.js"  file as a new MIME object in path SAP -> PUBLIC -> BC -> UI2 -> logon -> fiori3 -> js

      Ashutosh_Rai1_19-1759686903005.png

(7) Now we need to call this custom "zlogin_ext.js" JavaScript file in our custom ZCL_CUSTOM_FIORI_LOGIN ABAP class , for that update this ABAP class code as below 

CLASS zcl_custom_fiori_login DEFINITION
  PUBLIC
  INHERITING FROM /ui2/cl_fiori3_login
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
  PROTECTED SECTION.
    METHODS init_default_properties REDEFINITION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_custom_fiori_login IMPLEMENTATION.
   METHOD init_default_properties.

    super->init_default_properties( context ).
    m_properties->set( name = 'extra_js' value = '/sap/public/bc/ui2/logon/fiori3/js/zlogin_ext.js' ).

  ENDMETHOD.
ENDCLASS.

 (8) Now we can test our Logon screen by going to "SICF" tcode and running our custom service "ZCUSTOM_FIORI_L" which we have created for testing : 

      Ashutosh_Rai1_20-1759687271957.png  Ashutosh_Rai1_21-1759687314369.png   Ashutosh_Rai1_22-1759687411132.png

(9) Now we need to configure this in Standard Fiori Launchpad, for that follow below steps :

   (a) Goto "SICF" tcode and in "Service Name" enter "FLP" and double click on the entry 

       Ashutosh_Rai1_23-1759687581143.png

   (b) Switch to Edit mode 

     Ashutosh_Rai1_24-1759687693057.png

   (c) Navigate to Error pages, activate the System Logon radio button and click on Configuration

     Ashutosh_Rai1_25-1759687773654.png

    (d) In the System Logon Configuration menu, activate radio button: Define Service-Specific Settings followed by activating radio button Custom Implementation and entering the name of your custom class (in our case it is ZCL_CUSTOM_FIORI_LOGIN). Once done, click on Ok button and accept all messages.

     Ashutosh_Rai1_26-1759687919053.png

     (e) Once changes have been done, click on Save.

        NOTE - You will be prompted for a transport request

(10) Logon to the Fiori Launchpad(or you can directly use "/n/ui2/flp" tcode), you should now see the same new custom logon page which is been shown in step 8.