1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

M : #~: fix get JWT fireedge with 2fa (#1114)

Signed-off-by: Jorge Lobo <jlobo@opennebula.io>

Co-authored-by: Jorge Lobo <jlobo@opennebula.systems>
This commit is contained in:
Jorge Miguel Lobo Escalona 2021-04-16 12:17:46 +02:00 committed by Ruben S. Montero
parent 5a013ee2be
commit 0497d2936e
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
4 changed files with 95 additions and 72 deletions

View File

@ -15,15 +15,15 @@
/* -------------------------------------------------------------------------- */
define(function(require) {
require('../bower_components/jquery/dist/jquery.min');
var OpenNebulaAuth = require('opennebula/auth');
var WebAuthnJSON = require('../bower_components/webauthn-json/dist/index');
require("../bower_components/jquery/dist/jquery.min");
var OpenNebulaAuth = require("opennebula/auth");
var WebAuthnJSON = require("../bower_components/webauthn-json/dist/index");
var showErrorAuth = false;
var uid;
var textOpenNebulaNotRunning = "OpenNebula is not running or there was a server exception. Please check the server logs.";
var textInvalidUserorPassword = "Invalid username or password";
var textInvalidUserorPassword = "Invalid username or password";
var textNoAnswerFromServer = "No answer from server. Is it running?";
var textTwoFactorTokenInvalid = "Invalid second factor authentication";
var idElementTwoFactor = "#two_factor_auth_token";
@ -59,11 +59,11 @@ define(function(require) {
dataType: "json",
success: function (response) {
if (!response) {
return
return;
}
if (!navigator.credentials) {
$("#webauthn_login_div").hide();
console.warn('WebAuthn functionality unavailable. Ask your cloud administrator to enable TLS.');
console.warn("WebAuthn functionality unavailable. Ask your cloud administrator to enable TLS.");
}
$("#webauthn_login_btn").click(function () {
WebAuthnJSON.get({ "publicKey": response }).then(authenticate)
@ -71,13 +71,13 @@ define(function(require) {
$("#error_message").text(e.message);
$("#error_box").fadeIn("slow");
$("#login_spinner").hide();
});
});
});
},
error: function (response) {
if (response.status == 501) {
$("#webauthn_login_div").hide();
console.warn('WebAuthn functionality unavailable. Ask your cloud administrator to upgrade the Ruby version.');
console.warn("WebAuthn functionality unavailable. Ask your cloud administrator to upgrade the Ruby version.");
}
}
});
@ -116,13 +116,13 @@ define(function(require) {
var error_callback;
if (publicKeyCredential == undefined) {
two_factor_auth_token = $("#two_factor_auth_token").val();
error_callback = auth_error
error_callback = auth_error;
} else {
two_factor_auth_token = JSON.stringify(publicKeyCredential);
error_callback = function(req, error) {
auth_error(req, error);
prepareWebAuthn(uid);
}
};
}
$("#error_box").fadeOut("slow");
@ -144,7 +144,7 @@ define(function(require) {
// Returns the version of Internet Explorer or a -1
// (indicating the use of another browser).
var rv = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer') {
if (navigator.appName == "Microsoft Internet Explorer") {
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})");
if (re.exec(ua) != null)
@ -161,19 +161,19 @@ define(function(require) {
Please upgrade or use Firefox or Chrome for full compatibility." :
"OpenNebula Sunstone is best seen with Chrome or Firefox";
$("#error_box").text(msg);
$("#error_box").fadeIn('slow');
$("#error_box").fadeIn("slow");
}
}
function limitToken(){
$(idElementTwoFactor).off('input').on('input', function() {
$(idElementTwoFactor).off("input").on("input", function() {
var element = $(this);
if(element.attr("maxlength") && element.attr("maxlength") > 0){
var value = element.val().replace(/[^0-9.]/g, '')
var value = element.val().replace(/[^0-9.]/g, "");
if (value.length > element.attr("maxlength")){
element.val(value.substr(0,15))
element.val(value.substr(0,15));
}else{
element.val(value)
element.val(value);
}
}
});
@ -195,9 +195,9 @@ define(function(require) {
//compact login elements according to screen height
if (screen.height <= 600) {
$('div#logo_sunstone').css("top", "15px");
$('div#login').css("top", "10px");
$('.error_message').css("top", "10px");
$("div#logo_sunstone").css("top", "15px");
$("div#login").css("top", "10px");
$(".error_message").css("top", "10px");
};
$("input#username.box").focus();

View File

@ -91,16 +91,16 @@ define(function (require) {
var error_function = function(error, request=null, notify=true){
if (notify)
Notifier.onError(request, {error:{ message: "FireEdge public endpoint is not working, please contact your cloud administrator"}});
sunstone_fireedge_active = false;
if (typeof error === "function")
error();
}
};
var _check_fireedge_public_url = function (success, aux, error) {
var regex = /^(http(s)?:\/\/)(www\.)?[a-z,0-9]+([\-\.]{1}[a-z,0-9]+)*(:[0-9]{1,5})?(\/.*)?$/gm
var valid_endpoint = Boolean(fireedge_endpoint.match(regex))
var regex = /^(http(s)?:\/\/)(www\.)?[a-z,0-9]+([\-\.]{1}[a-z,0-9]+)*(:[0-9]{1,5})?(\/.*)?$/gm;
var valid_endpoint = Boolean(fireedge_endpoint.match(regex));
if (fireedge_endpoint && valid_endpoint){
$.ajax({

View File

@ -344,7 +344,7 @@ define(function(require) {
if (defaults[key] != undefined){
attrs.initial = opts.defaults[key];
}
if(checkItemInArray(attrs, store, 'name')){
if(checkItemInArray(attrs, store, "name")){
store.push(attrs);
}
});
@ -371,10 +371,10 @@ define(function(require) {
var separator = $("<div>");
$.each(network_attrs, function(index, vnet_attr) {
// 0 type; 1 id; 3(optional) extra
var info = vnet_attr.initial.split(":")
var info = vnet_attr.initial.split(":");
var type = info[0];
var id = info[1];
var extra = info.slice(2).join('');
var extra = info.slice(2).join("");
var unique_id = "vnet_user_input_" + UniqueId.id();
if(type === "reserve_from" || type === "id") {
@ -393,10 +393,10 @@ define(function(require) {
$("<div>",{class:"columns small-12"}).append(
$("<select>",{
class: "changePlaceDatatable",
wizard_field: 'type_'+vnet_attr.name,
'data-nametable': vnet_attr.name,
'data-idtable': unique_id,
'data-id': index
wizard_field: "type_"+vnet_attr.name,
"data-nametable": vnet_attr.name,
"data-idtable": unique_id,
"data-id": index
}).append(
$("<option>",{ value: "id" }).text(Locale.tr("Existing")
).add(
@ -426,24 +426,24 @@ define(function(require) {
table.idInput().attr("wizard_field", vnet_attr.name).attr("required", "");
// Fill type, id of vnet/vnet-template and extra
$(".changePlaceDatatable[data-id="+index+"]").val(type)
table.selectResourceTableSelect({ 'ids': String(id) })
$(".changePlaceDatatable[data-id="+index+"]").val(type);
table.selectResourceTableSelect({ "ids": String(id) });
if (type === "template_id" || type === "reserve_from") {
$("#placeDatatable_"+index).append(
$("<div/>",{'class': "row addExtra_"+id}).append(
$("<div/>",{'class': "columns small-12"}).append(
$("<div/>",{"class": "row addExtra_"+id}).append(
$("<div/>",{"class": "columns small-12"}).append(
$("<label/>").text(Locale.tr("Extra")).add(
$("<input/>",{
'wizard_field': "extra_"+vnet_attr.name,
'type': "text",
'name': "extra",
'id': "extra",
'placeholder': Locale.tr("Extra")
"wizard_field": "extra_"+vnet_attr.name,
"type": "text",
"name": "extra",
"id": "extra",
"placeholder": Locale.tr("Extra")
}).val(extra)
)
)
)
)
);
}
});
if(opts && opts.select_networks){
@ -551,7 +551,7 @@ define(function(require) {
//render Vmgroups_attr_values
if (vmgroups_attrs.length > 0 && opts.role) {
var options = '<option value="">'+Locale.tr("Without VM Group")+'</option>';
var options = "<option value=\"\">"+Locale.tr("Without VM Group")+"</option>";
vmgroups_attrs.map(function(vmgroup){
if(
vmgroup &&
@ -561,7 +561,7 @@ define(function(require) {
vmgroup.VM_GROUP.TEMPLATE
){
vmGroupDescription = vmgroup.VM_GROUP.TEMPLATE.DESCRIPTION? "("+vmgroup.VM_GROUP.TEMPLATE.DESCRIPTION+")": "";
options += "<option value='"+vmgroup.VM_GROUP.ID+"'>"+vmgroup.VM_GROUP.NAME+vmGroupDescription+"</option>"
options += "<option value='"+vmgroup.VM_GROUP.ID+"'>"+vmgroup.VM_GROUP.NAME+vmGroupDescription+"</option>";
}
});
@ -718,8 +718,8 @@ define(function(require) {
if (attr.type == "range"){
attr.tick_size = 1024;
}
var select = '';
var selectInput = editUnit? '': 'disabled';
var select = "";
var selectInput = editUnit? "": "disabled";
if(displayUnit){
var select = "<select class=\"mb_input_unit\" "+selectInput+">" +
"<option value=\"MB\">"+Locale.tr("MB")+"</option>" +
@ -733,7 +733,7 @@ define(function(require) {
"<div class=\"mb_input input-group-field\">" +
_attributeInput(attr) +
"</div>"+
"<div class=\"input-group-button\">"+
"<div class=\"input-group-button\">"+
select+
"</div>"+
"</div>");
@ -746,26 +746,27 @@ define(function(require) {
var unit = "MB";
var valueInMB = 0;
var contextElement = $("div.mb_input", context);
// Fill in the input with your unit the first time
$("input, select", contextElement).trigger("input");
var element = $("input.uinput-slider-val", contextElement);
var value = element.val();
var valueInUnit = value;
var min = parseInt(element.attr("min"),10);
var max = parseInt(element.attr("max"),10);
if (value == ""){
$(".mb_input_unit", context).val("MB").trigger("change");
}else{
// If you are going to put a new unit you must put it up in the html, here and down in the change
if(value / (base**2) >= 1){
baseCal = base**2;
if(value / (base*base) >= 1){
baseCal = base*base;
unit = "TB";
}else if(value / base >= 1){
baseCal = base;
unit = "GB";
}
if (value && value.length > 0) {
valueInMB = value
valueInMB = value;
if(!isNaN(min) && parseInt(min, 10) > valueInMB ){
valueInMB = min;
}
@ -785,11 +786,11 @@ define(function(require) {
var valueInUnit = value;
var mb_input_unit_val = $(".mb_input_unit :selected", context).val();
switch (mb_input_unit_val) {
case 'TB':
baseCal = base**2;
case "TB":
baseCal = base*base;
unit = "TB";
break;
case 'GB':
case "GB":
baseCal = base;
unit = "GB";
break;
@ -836,7 +837,7 @@ define(function(require) {
value = TemplateUtils.htmlEncode(attr.initial);
}
if(attr.visor){
clss = "hide"
clss = "hide";
}
switch (attr.type) {
case "text64":
@ -857,7 +858,7 @@ define(function(require) {
input += Locale.tr("NO ") + "<input type='radio' name='bool_" + id + "' value='NO'" + wizard_field + " " + required + "/>";
} else if(value == "NO"){
input = "<br>" + Locale.tr("YES ") + "<input style='margin-right: 20px' type='radio' name='bool_" + id + "' value='YES'" + wizard_field + " " + required + "/>";
input += Locale.tr("NO ") + "<input checked type='radio' name='bool_" + id + "' value='NO'" + wizard_field + " " + required + "/>"
input += Locale.tr("NO ") + "<input checked type='radio' name='bool_" + id + "' value='NO'" + wizard_field + " " + required + "/>";
} else {
input = "<br>" + Locale.tr("YES ") + "<input style='margin-right: 20px' type='radio' name='bool_" + id + "' value='YES'" + wizard_field + " " + required + "/>";
input += Locale.tr("NO ") + "<input type='radio' name='bool_" + id + "' value='NO'" + wizard_field + " " + required + "/>";
@ -902,7 +903,7 @@ define(function(require) {
break;
}
if(attr.visor){
input += '<input type="number" class="visor" value="'+value+'" required>';
input += "<input type=\"number\" class=\"visor\" value=\""+value+"\" required>";
}
return input;
}

View File

@ -366,6 +366,30 @@ helpers do
}
end
def get_fireedge_token(tfa)
response = ""
if $conf && $conf[:private_fireedge_endpoint] && !$conf[:private_fireedge_endpoint].empty?
begin
uri = URI($conf[:private_fireedge_endpoint]+'/fireedge/api/auth')
user_pass = Base64.decode64(session[:auth])
username = user_pass.split(":")[0]
password = user_pass.split(":")[1]
params = { :user => username, :token => password }
if tfa && !tfa.empty?
params[:token2fa] = tfa
end
fireedge_token = ""
res = Net::HTTP.post_form(uri, params)
fireedge_token = JSON.parse(res.body)['data']['token'] if res.is_a?(Net::HTTPSuccess)
response = fireedge_token
rescue StandardError => error
logger.error { "Cannot connect with fireedge: #{error.message}" }
end
end
return response
end
def build_session
begin
result = $cloud_auth.auth(request.env, params)
@ -391,8 +415,8 @@ helpers do
# two factor_auth
isHOTPConfigured = (user[TWO_FACTOR_AUTH_SECRET_XPATH] && user[TWO_FACTOR_AUTH_SECRET_XPATH] != "")
isWebAuthnConfigured = $conf[:webauthn_avail] && SunstoneWebAuthn.getCredentialIDsForUser(user.id).length > 0
two_factor_auth_token = params[:two_factor_auth_token]
if isHOTPConfigured || isWebAuthnConfigured
two_factor_auth_token = params[:two_factor_auth_token]
if !two_factor_auth_token || two_factor_auth_token == ""
return [202, { code: "two_factor_auth", uid: user.id }.to_json]
end
@ -508,6 +532,9 @@ helpers do
auth = request.env['HTTP_AUTHORIZATION'].match(/(?<basic>\w+) (?<pass>\w+)/)
session[:auth] = auth[:pass]
#get firedge JWT
session[:fireedge_token] = get_fireedge_token(two_factor_auth_token)
[204, ""]
end
@ -919,24 +946,19 @@ end
# GET FireEdge token
##############################################################################
get '/fireedge' do
begin
uri = URI($conf[:private_fireedge_endpoint]+'/fireedge/api/auth')
user_pass = Base64.decode64(session[:auth])
username = user_pass.split(":")[0]
password = user_pass.split(":")[1]
params = { :user => username, :token => password }
fireedge_token = ""
res = Net::HTTP.post_form(uri, params)
fireedge_token = JSON.parse(res.body)['data']['token'] if res.is_a?(Net::HTTPSuccess)
if !session[:fireedge_token].empty?
response = {:token => session[:fireedge_token]}
[200, response.to_json]
else
fireedge_token = get_fireedge_token("")
if !fireedge_token.empty?
session[:fireedge_token] = fireedge_token
response = {:token => fireedge_token}
[200, response.to_json]
rescue StandardError => error
logger.info("FireEdge server is not running. Error: #{error}")
response = {:token => session[:fireedge_token]}
[200, response.to_json]
else
response = {:token => ""}
[400, response.to_json]
end
end
end