File: //proc/thread-self/root/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/mcollective/security/psk.rb
module MCollective
module Security
# Impliments message authentication using digests and shared keys
#
# You should configure a psk in the configuration file and all requests
# will be validated for authenticity with this.
#
# Serialization uses Marshal, this is the default security module that is
# supported out of the box.
#
# Validation is as default and is provided by MCollective::Security::Base
#
# You can configure the caller id being created, this can adjust how you
# create authorization plugins. For example you can use a unix group instead
# of uid to do authorization.
class Psk < Base
require 'etc'
# Decodes a message by unserializing all the bits etc, it also validates
# it as valid using the psk etc
def decodemsg(msg)
body = Marshal.load(msg.payload)
should_process_msg?(msg, body[:requestid])
if validrequest?(body)
body[:body] = Marshal.load(body[:body])
return body
else
nil
end
end
# Encodes a reply
def encodereply(sender, msg, requestid, requestcallerid=nil)
serialized = Marshal.dump(msg)
digest = makehash(serialized)
req = create_reply(requestid, sender, serialized)
req[:hash] = digest
Marshal.dump(req)
end
# Encodes a request msg
def encoderequest(sender, msg, requestid, filter, target_agent, target_collective, ttl=60)
serialized = Marshal.dump(msg)
digest = makehash(serialized)
req = create_request(requestid, filter, serialized, @initiated_by, target_agent, target_collective, ttl)
req[:hash] = digest
Marshal.dump(req)
end
# Checks the md5 hash in the request body against our psk, the request sent for validation
# should not have been deserialized already
def validrequest?(req)
digest = makehash(req[:body])
if digest == req[:hash]
@stats.validated
return true
else
@stats.unvalidated
raise(SecurityValidationFailed, "Received an invalid signature in message")
end
end
def callerid
if @config.pluginconf.include?("psk.callertype")
callertype = @config.pluginconf["psk.callertype"].to_sym if @config.pluginconf.include?("psk.callertype")
else
callertype = :uid
end
case callertype
when :gid
id = "gid=#{Process.gid}"
when :group
raise "Cannot use the 'group' callertype for the PSK security plugin on the Windows platform" if Util.windows?
id = "group=#{Etc.getgrgid(Process.gid).name}"
when :user
id = "user=#{Etc.getlogin}"
when :identity
id = "identity=#{@config.identity}"
else
id ="uid=#{Process.uid}"
end
Log.debug("Setting callerid to #{id} based on callertype=#{callertype}")
id
end
private
# Retrieves the value of plugin.psk and builds a hash with it and the passed body
def makehash(body)
if ENV.include?("MCOLLECTIVE_PSK")
psk = ENV["MCOLLECTIVE_PSK"]
else
raise("No plugin.psk configuration option specified") unless @config.pluginconf.include?("psk")
psk = @config.pluginconf["psk"]
end
Digest::MD5.hexdigest(body.to_s + psk)
end
end
end
end