Example for Ciphertext Passing Through Frontend SSO

  • Last update:  2024-06-24
  • Overview

    Version

    Report Server Version

    11.0

    Problem Description

    On the custom login page, you need to send the entered plaintext password to the decision-making platform for login verification. During the passing procedure, the plaintext password is of low security. As a result, you may want to encrypt the password and ensure information security through SSO.

    Implementation Method

    Encrypt the password entered by the user on the login page through the encryption algorithm, and pass the ciphertext to the decision-making platform for login verification.

    The database stores the encrypted ciphertext, and information in the database can be stored on the decision-making platform through User Synchronization. When the passed ciphertext is consistent with the stored one, the login verification is passed, making the user log in to the decision-making platform successfully.

    Implementation Step

    1. Prepare the encrypted JS file to encrypt the plaintext entered on the login page by the user.

    2. Create an HTML file and customize the login page to achieve the following effects:

    Reference the encrypted JS file prepared in step 1 and call the encryption method to convert the plaintext entered to ciphertext.

    Call the SSO interface to pass the ciphertext to the decision-making platform for login verification.

    After the successful login verification, jump to the user's decision-making platform page.

    3. Place the HTML file and encrypted JS file in the specified location.

    4. Create a server dataset to store user login information, including username and login password (an encrypted ciphertext B).

    iconNote:
    After the user synchronization, the system performs a SHA256 encryption on ciphertext B in the server dataset and writes the resulting ciphertext into the database FineDB.

    5. Synchronize the user information to the decision-making platform for login verification.

    Example

    Example in this document: Customize a decision-making platform login page, encrypt the password entered by the user through the MD5 (16 uppercase digits) encryption, perform the login verification through the encrypted ciphertext, and jump to the user's decision-making platform after the verification is passed.

    Encrypted JS File Preparation

    Prepare the encrypted JS file to encrypt the plaintext password entered on the login platform.

    Create a JS file named MD5.js, the code is shown below.

    You can download and decompress the package to obtain the encrypted JS files: Encryption.rar.

    iconNote:
    Besides, this package contains SHA256.js encryption files. You can select the files as needed. For details about using the files, see the example in this section.
    var hexcase = 1;
    var b64pad = "";
    var chrsz = 8;
    var mode = 16; //Mode selection (16: encryption with base 16; 32:  encryption with base 32)
    function preprocess(form)
    {
    var str = "";
    str += form.verifycode.value;
    str = str.toUpperCase();
    form.p.value = md5(md5_3(form.p.value)+str);
    return true;
    }
    function md5_3(s)
    {
    var tmp = new Array;
    tmp = core_md5(str2binl(s), s.length * chrsz);
    tmp = core_md5(tmp, 16 * chrsz);
    tmp = core_md5(tmp, 16 * chrsz);
    return binl2hex(tmp);
    }
    function md5(s)
    {
    return hex_md5(s);
    }
    function hex_md5(s)
    {
    return binl2hex(core_md5(str2binl(s), s.length * chrsz));
    }
    function b64_md5(s)
    {
    return binl2b64(core_md5(str2binl(s), s.length * chrsz));
    }
    function str_md5(s)
    {
    return binl2str(core_md5(str2binl(s), s.length * chrsz));
    }
    function hex_hmac_md5(key, data)
    {
    return binl2hex(core_hmac_md5(key, data));
    }
    function b64_hmac_md5(key, data)
    {
    return binl2b64(core_hmac_md5(key, data));
    }
    function str_hmac_md5(key, data)
    {
    return binl2str(core_hmac_md5(key, data));
    }
    function md5_vm_test()
    {
    return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
    }
    function core_md5(x, len)
    {
    x[len >> 5] |= 0x80 << ((len) % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;
    var a = 1732584193;
    var b = - 271733879;
    var c = - 1732584194;
    var d = 271733878;
    for (var i = 0; i < x.length; i += 16)
    {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;
    a = md5_ff(a, b, c, d, x[i + 0], 7, - 680876936);
    d = md5_ff(d, a, b, c, x[i + 1], 12, - 389564586);
    c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
    b = md5_ff(b, c, d, a, x[i + 3], 22, - 1044525330);
    a = md5_ff(a, b, c, d, x[i + 4], 7, - 176418897);
    d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
    c = md5_ff(c, d, a, b, x[i + 6], 17, - 1473231341);
    b = md5_ff(b, c, d, a, x[i + 7], 22, - 45705983);
    a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
    d = md5_ff(d, a, b, c, x[i + 9], 12, - 1958414417);
    c = md5_ff(c, d, a, b, x[i + 10], 17, - 42063);
    b = md5_ff(b, c, d, a, x[i + 11], 22, - 1990404162);
    a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
    d = md5_ff(d, a, b, c, x[i + 13], 12, - 40341101);
    c = md5_ff(c, d, a, b, x[i + 14], 17, - 1502002290);
    b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
    a = md5_gg(a, b, c, d, x[i + 1], 5, - 165796510);
    d = md5_gg(d, a, b, c, x[i + 6], 9, - 1069501632);
    c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
    b = md5_gg(b, c, d, a, x[i + 0], 20, - 373897302);
    a = md5_gg(a, b, c, d, x[i + 5], 5, - 701558691);
    d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
    c = md5_gg(c, d, a, b, x[i + 15], 14, - 660478335);
    b = md5_gg(b, c, d, a, x[i + 4], 20, - 405537848);
    a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
    d = md5_gg(d, a, b, c, x[i + 14], 9, - 1019803690);
    c = md5_gg(c, d, a, b, x[i + 3], 14, - 187363961);
    b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
    a = md5_gg(a, b, c, d, x[i + 13], 5, - 1444681467);
    d = md5_gg(d, a, b, c, x[i + 2], 9, - 51403784);
    c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
    b = md5_gg(b, c, d, a, x[i + 12], 20, - 1926607734);
    a = md5_hh(a, b, c, d, x[i + 5], 4, - 378558);
    d = md5_hh(d, a, b, c, x[i + 8], 11, - 2022574463);
    c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
    b = md5_hh(b, c, d, a, x[i + 14], 23, - 35309556);
    a = md5_hh(a, b, c, d, x[i + 1], 4, - 1530992060);
    d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
    c = md5_hh(c, d, a, b, x[i + 7], 16, - 155497632);
    b = md5_hh(b, c, d, a, x[i + 10], 23, - 1094730640);
    a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
    d = md5_hh(d, a, b, c, x[i + 0], 11, - 358537222);
    c = md5_hh(c, d, a, b, x[i + 3], 16, - 722521979);
    b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
    a = md5_hh(a, b, c, d, x[i + 9], 4, - 640364487);
    d = md5_hh(d, a, b, c, x[i + 12], 11, - 421815835);
    c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
    b = md5_hh(b, c, d, a, x[i + 2], 23, - 995338651);
    a = md5_ii(a, b, c, d, x[i + 0], 6, - 198630844);
    d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
    c = md5_ii(c, d, a, b, x[i + 14], 15, - 1416354905);
    b = md5_ii(b, c, d, a, x[i + 5], 21, - 57434055);
    a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
    d = md5_ii(d, a, b, c, x[i + 3], 10, - 1894986606);
    c = md5_ii(c, d, a, b, x[i + 10], 15, - 1051523);
    b = md5_ii(b, c, d, a, x[i + 1], 21, - 2054922799);
    a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
    d = md5_ii(d, a, b, c, x[i + 15], 10, - 30611744);
    c = md5_ii(c, d, a, b, x[i + 6], 15, - 1560198380);
    b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
    a = md5_ii(a, b, c, d, x[i + 4], 6, - 145523070);
    d = md5_ii(d, a, b, c, x[i + 11], 10, - 1120210379);
    c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
    b = md5_ii(b, c, d, a, x[i + 9], 21, - 343485551);
    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
    }
    if (mode == 16)
    {
    return Array(b, c);
    }
    else
    {
    return Array(a, b, c, d);
    }
    }
    function md5_cmn(q, a, b, x, s, t)
    {
    return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
    }
    function md5_ff(a, b, c, d, x, s, t)
    {
    return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
    }
    function md5_gg(a, b, c, d, x, s, t)
    {
    return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
    }
    function md5_hh(a, b, c, d, x, s, t)
    {
    return md5_cmn(b ^ c ^ d, a, b, x, s, t);
    }
    function md5_ii(a, b, c, d, x, s, t)
    {
    return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
    }
    function core_hmac_md5(key, data)
    {
    var bkey = str2binl(key);
    if (bkey.length > 16)
    bkey = core_md5(bkey, key.length * chrsz);
    var ipad = Array(16), opad = Array(16);
    for (var i = 0; i < 16; i++)
    {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }
    var hash = core_md5(ipad.concat(str2binl(data)), 512+data.length * chrsz);
    return core_md5(opad.concat(hash), 512+128);
    }
    function safe_add(x, y)
    {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
    }
    function bit_rol(num, cnt)
    {
    return (num << cnt) | (num >>> (32-cnt));
    }
    function str2binl(str)
    {
    var bin = Array();
    var mask = (1 << chrsz) - 1;
    for (var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
    return bin;
    }
    function binl2str(bin)
    {
    var str = "";
    var mask = (1 << chrsz) - 1;
    for (var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
    return str;
    }
    function binl2hex(binarray)
    {
    var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var str = "";
    for (var i = 0; i < binarray.length * 4; i++)
    {
    str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8+4)) & 0xF) +
    hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
    }
    return str;
    }
    function binl2b64(binarray)
    {
    var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var str = "";
    for (var i = 0; i < binarray.length * 4; i += 3)
    {
    var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16) | ((
    (binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8) | ((binarray[i
    + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
    for (var j = 0; j < 4; j++)
    {
    if (i * 8+j * 6 > binarray.length * 32)
    str += b64pad;
    else
    str += tab.charAt((triplet >> 6 * (3-j)) & 0x3F);
    }
    }
    return str;
    }

    After introducing MD5.js file on the custom login page created in section "Login Page Creation", you can directly call the MD5 encryption method through the doSubmit() function to encrypt the entered plaintext password.

    The usage is shown as follows.

    iconNote:
    MD5.js provides six encryption methods, including hex_md5(value), b64_md5(value), str_md5(value), hex_hmac_md5(key, data), b64_hmac_md5(key, data), and str_hmac_md5(key, data). You can select the method as needed.
    <script type="text/javascript" src="./md5.js"></script>  //Introduce MD5.js
    var password = md5(document.getElementById("password").value.trim()); //Encrypt the entered password with the MD5 encryption method

    Login Page Creation

    Create a custom decision-making platform login page (HTML file) named Login.html. The complete code is shown as follows.

    iconNote:
    You need to modify the access path or port number in the code according to the actual situation.

    You can download and decompress the HTML files: Login.rar.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Custom Login Page Encryption Demo</title>

        <!-- Custom Style According to Actual Requirements -->
        <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
        <script type="text/javascript" src="https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js"></script>
        
        <script type="text/javascript" src="./md5.js"></script>

        <style>
            .container {
                display: flex;
                justify-content: center;
            }
            .login-box {
                width: 300px;
                margin-top: 100px;
            }
            .login-box h2 {
                font-size: 26px;
                text-align: center;
                margin-bottom: 25px;
            }
            .login-item {
                margin-bottom: 20px;
            }
        </style>
    <body>
    <div class="container">
        <form class="login-box" action="" method="post" onsubmit="return false;">
            <h2>Decision-making Platform</h2>
            <div class="login-item">
                <label for="inputUsername" class="sr-only">Username</label>
                <input type="text" id="inputUsername" class="form-control" placeholder="Username" required="" autofocus="">
            </div>
            <div class="login-item">
                <label for="inputPassword" class="sr-only">Password</label>
                <!--  autocomplete="off"Attribute, prevents the browser getting the data entry login form through cookies -->
                <input type="text" id="inputPassword" οnfοcus="this.type='password'" class="form-control" placeholder="Password" required="" autocomplete="off">
            </div>
            <button class="btn btn-lg btn-primary btn-block" type="submit" id="submitBtn">Login</button>
        </form>
    </div>
    <script>
        document.getElementById("submitBtn").addEventListener("click", function () {
            doSubmit();
        });
            function doSubmit() {
                var username = document.getElementById("inputUsername").value.trim();
                var password = md5(document.getElementById("inputPassword").value.trim()); //Encrypt the password entered by the user
                if (username === "") {
                    window.alert("Enter the username");
                    return false;
                }
                if (password === "") {
                    window.alert("Enter the password");
                    return false;
                }
                var url = "http://localhost:8075/webroot/decision/login/cross/domain" + "?fine_username=" + username + "&fine_password=" + password + "&validity=" + -1;
                jQuery.ajax({
                    url: url,//SSO Management Platform Report Server
                    timeout: 5000,//Time-out period (Unit: Millisecond)
                    dataType:"jsonp",//Cross-domain through the jsonp method
                    jsonp:"callback",
                    success: function (res) {
                        console.log(res);
                        if (res.errorCode) {
                            window.alert(res.errorMsg);
                        }else {
                            // Save the token and jump to the corresponding link
                            window.location.href = "http://localhost:8075/webroot/decision";
                        }
                    },
                    error: function () {
                        alert("Time-out or other server error");// Login failure (time-out or other server error)  
                    }
                });
            }
    </script>
    </body>
    </html>

    Specified File Location Placing

    Save the Login.html and md5.js files under the path %FR_HOME%/webapps/webroot, as shown in the following figure.

    Database Information Synchronization to the Decision-Making Platform

    Preparing the data

    Prepare a user information table where the content in the Password data column is the ciphertext encrypted with MD5 (16 uppercase digits). The following figure shows the table structure.

    Example: If the user a enters the plaintext password 123456, the password stored in the Password column is 49BA59ABBE56E057, ciphertext encrypted with MD5 (16 uppercase digits).

    You can click and download the table: User Synchronization.xlsx.

    Adding a Server Dataset

    You can use a third-party database management tool to import the above table into a database and establish a data connection between the decision-making platform and the database. Besides, you can create a database and import the table into the database. The following content takes a created database Data Connection as an example.

    1. Log in to the decision-making platform as the admin, choose System Management > Data Connection > Server Dataset, click Create Dataset, and select SQL Dataset from the drop-down list.

    2. Set Dataset Name to User Synchronization, set Data from Data Connection to Data Connection, and enter the following SQL statement.

    SELECT * FROM "User Synchronization"

    Synchronizing the User

    1. Log in to the decision-making platform as the admin, choose System Management > User Management > All Users, and click Synchronize User.

    A prompt box displaying "Sure to retain existing asynchronous data, including imported/added users, departments, positions, and roles?" pops up, as shown in the following figure.

    iconNote:
    1. This section introduces the data update rules for users performing an initial Synchronize User or an initial Synchronize User with User Synchronization not enabled. If users have performed Synchronize User or non-initial Synchronize User with User Synchronization enabled before, the prompt box will not pop up, and the synchronization will not be performed based on the update rules in this section.
    2. The synchronized users can coexist with manually added/imported users.

    The following table shows the update logic corresponding to different selections.

    SelectionDefinition

    Retain

    If the existing user is not in the synchronized server dataset, the user's information and permissions will be retained without modification.

    If the existing user (with the same username) is in the synchronized server dataset:

    The user's username will remain unchanged, with permissions retained.

    The user's username, password, phone number, and email address will be updated.

    If the user's current department, position, and role exist in the synchronized server dataset, all the above information will be updated.

    If the user's current department, position, and role are not in the synchronized server dataset, all the above information will remain unchanged.

    Clear

    All the usernames, names, passwords, phone numbers, email addresses, departments, positions, roles, and permissions of users (manually added or imported into the platform) will be deleted. Users need to be resynchronized.

    iconNote:

    Based on the update logic, if some user information is updated after the initial synchronization,

    only users (changed to the synchronous type) can be automatically updated in the later synchronization.

    For subsequent synchronizations, the dataset cannot overwrite or update built-in data. Otherwise, conflicts and error messages appear.


    2. Configure the user synchronization.

    Set User Source to User Synchronization, the dataset prepared in section "Adding a Server Dataset"

    Set Password to Password.

    Set Encryption Method to Built-in SHA Encryption.

    Click OK to complete the user synchronization.

    Effect Display

    User a accesses the link http://localhost:8075/webroot/login.html in the browser.

    Enter 123456 (plaintext password) on the login page and click Login to log in to the decision-making platform successfully.

    iconNote:
    You can add alert(url); to the code provided in section "Login Page Creation" to view the encrypted login effect.


    After you click the Login button, the frontend will process the entered login information as follows:

    1. Perform an MD5 encryption on the entered password, and the resulting ciphertext is used as the interface parameter.

    Example: If the entered password is 123456, the resulting plaintext after the MD5 encryption will be 49BA59ABBE56E057.

    2. Call the frontend SSO interface, and pass the user information to the decision-making platform for login verification.

    If the passed password is consistent with the password stored on the decision-making platform, you can access the decision-making platform successfully.

    Attachment List


    Theme: Deployment and Integration
    • Helpful
    • Not helpful
    • Only read

    滑鼠選中內容,快速回饋問題

    滑鼠選中存在疑惑的內容,即可快速回饋問題,我們將會跟進處理。

    不再提示

    10s後關閉

    Get
    Help
    Online Support
    Professional technical support is provided to quickly help you solve problems.
    Online support is available from 9:00-12:00 and 13:30-17:30 on weekdays.
    Page Feedback
    You can provide suggestions and feedback for the current web page.
    Pre-Sales Consultation
    Business Consultation
    Business: international@fanruan.com
    Support: support@fanruan.com
    Page Feedback
    *Problem Type
    Cannot be empty
    Problem Description
    0/1000
    Cannot be empty

    Submitted successfully

    Network busy