Project

General

Profile

Download (4.31 KB) Statistics
| Branch: | Tag: | Revision:
require 'gssapi'
require 'helpers'
require 'proxy/kerberos'
require 'proxy/util'
require 'uri'
require 'xmlrpc/client'

module Proxy::Realm
class FreeIPA < Client
include Proxy::Kerberos
include Proxy::Util

IPA_CONFIG = "/etc/ipa/default.conf"

def initialize
errors = []
errors << "keytab not configured" unless SETTINGS.realm_keytab
errors << "keytab not found: #{SETTINGS.realm_keytab}" unless SETTINGS.realm_keytab && File.exist?(SETTINGS.realm_keytab)
errors << "principal not configured" unless SETTINGS.realm_principal

logger.info "freeipa: realm keytab is '#{SETTINGS.realm_keytab}' and using principal '#{SETTINGS.realm_principal}'"

# Get FreeIPA Configuration
if File.exist?(IPA_CONFIG)
File.readlines(IPA_CONFIG).each do |line|
if line =~ /xmlrpc_uri/
@ipa_server = URI.parse line.split("=")[1].strip
logger.info "freeipa: server is #{@ipa_server}"
elsif line =~ /realm/
@realm_name = line.split("=")[1].strip
logger.info "freeipa: realm #{@realm_name}"
end
end
else
errors << "unable to read FreeIPA configuration: #{IPA_CONFIG}"
end

errors << "unable to parse client configuration" unless @ipa_server && @realm_name

if errors.empty?
# Get krb5 token
init_krb5_ccache SETTINGS.realm_keytab, SETTINGS.realm_principal
gssapi = GSSAPI::Simple.new(@ipa_server.host, "HTTP")
token = gssapi.init_context

# FreeIPA API returns some nils, Ruby XML-RPC doesn't like this
XMLRPC::Config.module_eval { const_set(:ENABLE_NIL_PARSER, true) }

@ipa = XMLRPC::Client.new2(@ipa_server.to_s)
@ipa.http_header_extra={ 'Authorization'=>"Negotiate #{strict_encode64(token)}",
'Referer' => @ipa_server.to_s,
'Content-Type' => 'text/xml; charset=utf-8'
}
else
raise Proxy::Realm::Error.new errors.join(", ")
end
end

def check_realm realm
raise Proxy::Realm::Error.new "Unknown realm #{realm}" unless realm.casecmp(@realm_name).zero?
end

def find hostname
@ipa.call("host_show", [hostname])
rescue XMLRPC::FaultException => e
if e.message =~ /not found/
nil
else
raise
end
end

def create realm, params
check_realm realm

options = { :setattr => [] }

# Send params to FreeIPA, may want to send more than one in the future
%w(userclass).each do |attr|
options[:setattr] << "#{attr}=#{params[attr]}" if params.has_key? attr
end

# Determine if we're updating a host or creating a new one
host = find params[:hostname]
if host.nil?
options.merge!(:random => 1, :force => 1)
operation = "host_add"
else
if params[:rebuild] == "true"
options.merge!(:random => 1)
# If the host is being rebuilt and is already enrolled, then
# disable it in order to revoke existing certs, keytabs, etc.
if host["result"]["has_keytab"]
logger.info "Attempting to disable host #{params[:hostname]} in FreeIPA"
@ipa.call("host_disable", [params[:hostname]])
end
end
operation = "host_mod"
end

begin
result = @ipa.call(operation, [params[:hostname]], options)
rescue => e
if e.message =~ /no modifications/
result = {"result" => {"message" => "nothing to do"}}
else
raise
end
end

JSON.pretty_generate(result["result"])
end

def delete realm, hostname
check_realm realm
raise Proxy::Realm::NotFound, "Host #{hostname} not found in realm!" unless find hostname
begin
result = @ipa.call("host_del", [hostname], {"updatedns" => SETTINGS.freeipa_remove_dns})
rescue => e
if SETTINGS.freeipa_remove_dns
# If the host doesn't have a DNS record (e.g. deleting a system in Foreman before it's built)
# the above call will fail. Try again with updatedns => false
result = @ipa.call("host_del", [hostname], {"updatedns" => false})
else
raise
end
end
JSON.pretty_generate(result)
end
end
end
    (1-1/1)