#!/usr/bin/env ruby require 'rubygems' require 'omf_rc' require 'omf_common' require 'yaml' require "net/https" require "uri" require "json" require 'time' $stdout.sync = true @config = YAML.load_file('/etc/nitos_testbed_rc/cm_proxy_conf.yaml') # @config = YAML.load_file(File.join(File.dirname(File.expand_path(__FILE__)), '../etc/cm_proxy_conf.yaml')) @auth = @config[:auth] @xmpp = @config[:xmpp] require 'nitos_testbed_rc/cm_factory' cm_entity_cert = File.expand_path(@auth[:entity_cert]) cm_entity_key = File.expand_path(@auth[:entity_key]) cm_entity = OmfCommon::Auth::Certificate.create_from_pem(File.read(cm_entity_cert))#, File.read(cm_entity_key)) trusted_roots = File.expand_path(@auth[:root_cert_dir]) opts = { communication: { url: "xmpp://#{@xmpp[:username]}:#{@xmpp[:password]}@#{@xmpp[:server]}", auth: { authenticate: true, pdp: { constructor: 'CmPDP' } } } } class CmPDP def initialize(opts = {}) debug "AUTH INIT>>> #{opts}" @config = YAML.load_file('/etc/nitos_testbed_rc/cm_proxy_conf.yaml') # @config = YAML.load_file(File.join(File.dirname(File.expand_path(__FILE__)), '../etc/cm_proxy_conf.yaml')) end def authorize(msg, &block) debug "AUTH message received: #{msg.operation}" if msg.operation.to_sym == :configure acc = _get_account_name(msg) if acc.nil? error "AUTH error: Account not found" msg.properties.state.error_msg = "Account name not found" return msg# next end node_name = msg.properties.state.node broker = @config[:broker_url] uri = URI.parse("#{broker}/resources/nodes?name=#{node_name}") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(uri.request_uri) response = http.request(request) resp = JSON.parse(response.body, :symbolize_names => true) if response.header.code != '200' if resp[:exception][:reason] == "No resources matching the request." error "AUTH error: Node #{node_name} does not exist." msg.properties.state.error_msg = "Node '#{node_name}' does not exist." else error "AUTH error: empty response" msg.properties.state.error_msg = "#{resp[:exception][:reason]} - code: '#{resp[:exception][:code]}'" end return msg# next end node = resp[:resource_response] if node.nil? error "AUTH error: Node '#{node_name}' not found" msg.properties.state.error_msg = "Node '#{node_name}' does not exist - code: '#{resp[:exception][:code]}'" return msg end node = node[:resource] # if @config[:testbedDomain] != "ALL" && node[:domain] != @config[:testbedDomain] # debug "This node does not belong to the domain '#{@config[:testbedDomain]}'" # msg.properties.state.ignore_msg = true # return msg # end nod = {} nod[:node_name] = node[:name] node[:interfaces].each do |i| if i[:role] == "control" nod[:node_ip] = i[:ips].first[:address] nod[:node_mac] = i[:mac] elsif i[:role] == "cm_network" nod[:node_cm_ip] = i[:ip][:address] end end nod[:node_cm_ip] = node[:cmc][:ip][:address] if acc == 'root' debug "AUTH PASSED (root account)" msg.properties.state.node = nod return msg end lease = nil unless node[:leases].nil? node[:leases].each do |l| l = l[:lease] next if l[:account][:name] != acc if Time.parse(l[:valid_from]) <= Time.now && Time.parse(l[:valid_until]) >= Time.now lease = l break end end end if lease.nil? error "AUTH error: node not available" msg.properties.state.error_msg = "Node '#{node_name}' is not leased by your account." return msg else debug "AUTH PASSED" msg.properties.state.node = nod return msg end # wait = true # result = nil # OmfCommon.comm.subscribe(@config[:testbedTopic]) do |am_con| # acc = _get_account_name(msg) # if acc.nil? # error "AUTH error: acc nill" # msg.properties.state.error_msg = "Account name not found" # result = msg # wait = false # next # end # node_name = msg.properties.state.node # am_con.request([:nodes]) do |n_msg| # nodes = n_msg.read_property("nodes")[:resources] # node = nil # nodes.each do |n| # if n[:resource][:name].to_s == node_name.to_s # node = n # break # end # end # lease = nil # if node.nil? # error "AUTH error: Node nill" # msg.properties.state.error_msg = "Wrong node name." # result = msg # wait = false # next # else # am_con.request([:leases]) do |l_msg| # leases = l_msg.read_property("leases")[:resources] # leases.each do |l| # if Time.parse(l[:resource][:valid_from]) <= Time.now && Time.parse(l[:resource][:valid_until]) >= Time.now # unless l[:resource][:components].nil? # l[:resource][:components].each do |c| # if c[:component][:name] == node_name.to_s && l[:resource][:account][:name] == acc # lease = l # break #found the correct lease # end # end # end # end # end # if lease.nil? #if lease is nil it means no matching lease is found # error "AUTH error: Lease nill" # msg.properties.state.error_msg = "Node is not leased by your account." # result = msg # wait = false # next # else # debug "AUTH PASSED" # msg.properties.state.node = node # result = msg # wait = false # next # end # end # end # end # end # #waiting for the whole process to be completed # while wait # sleep 1 # end # return result if result else debug "AUTH PASSED" return msg end # msg end private def _get_account_name(msg) #subject is ~ /C=US/ST=CA/O=ACME/OU=Roadrunner/CN=37a96f60-c53d-50d9-bbbf-3c552b89bdc5/emailAddress=root@nitlab.inf.uth.gr subj = msg.issuer.subject.to_s subj.gsub!(/.*CN=/, '') subj.gsub!(/.*emailAddress=/, '') subj.gsub!(/@.*/, '') debug "AUTH user: #{subj}" return subj end end OmfCommon.init(@config[:operationMode], opts) do |el|#communication: { url: "xmpp://#{@xmpp[:proxy_user]}:#{@xmpp[:password]}@#{@xmpp[:server]}", auth: {} }) do OmfCommon.comm.on_connected do |comm| OmfCommon::Auth::CertificateStore.instance.register_default_certs(trusted_roots) cm_entity.resource_id = OmfCommon.comm.local_topic.address OmfCommon::Auth::CertificateStore.instance.register(cm_entity) info "CM Factory >> Connected to XMPP server" cmFact = OmfRc::ResourceFactory.create(:cm_factory, { uid: 'cm_factory', certificate: cm_entity }) comm.on_interrupted { cmFact.disconnect } end end