Overview
Version
FineBI Server Version |
---|
6.0 |
Problem Description
On the custom login page, you need to send the entered plaintext password to the FineBI system 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 FineBI system for login verification.
The database stores the encrypted ciphertext, and information in the database can be stored on the FineBI system 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 FineBI system 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 FineBI system for login verification.
After the successful login verification, jump to the user's FineBI system 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 (the encrypted ciphertext).

5. Synchronize the user information to the FineBI system for login verification.
Example
Example in this document: Customize a FineBI system 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 FineBI system page 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.

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.

<script type="text/javascript" src="./md5.js"></script> //Introduce MD5.jsvar password = md5(document.getElementById("password").value.trim()); //Encrypt the entered password with the MD5 encryption method
Login Page Creation
Create a custom FineBI system login page (HTML file) named Login.html. The complete code is shown as follows.

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>FineBI System</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 Placement
Save the Login.html and md5.js files under the path %BI_HOME%/webapps/webroot, as shown in the following figure.
Database Information Synchronization to the FineBI System
Preparing 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 FineBI system and the database. The following content takes a created database as an example.
1. Log in to the FineBI system 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 Users
1. Log in to the FineBI system 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.

The following table shows the update logic corresponding to different selections.
Selection | Definition |
---|---|
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 be 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. |

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:37799/webroot/login.html in the browser.
Enter 123456 (plaintext password) on the login page and click Login to log in to the FineBI system successfully.

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.
For 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 FineBI system for login verification.
If the passed password is consistent with the password stored on the FineBI system, you can access the FineBI system successfully.